<?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=Sarjona</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=Sarjona"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Sarjona"/>
	<updated>2026-07-28T03:03:42Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Grader_report_2014&amp;diff=64592</id>
		<title>Grader report 2014</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Grader_report_2014&amp;diff=64592"/>
		<updated>2025-02-24T07:13:45Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Grader report 2014&lt;br /&gt;
|state = Specification&lt;br /&gt;
|tracker = https://tracker.moodle.org/browse/MDL-25544&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=263318&lt;br /&gt;
|assignee = Moodle HQ&lt;br /&gt;
}}&lt;br /&gt;
{{Work in progress|forumurl=https://moodle.org/mod/forum/discuss.php?d=263318}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This document specifies the changes to be made to the core Grader report in Moodle 2.8.  The changes are focussed on improving usability and accessibility for teachers using Moodle gradebook on any platform.&lt;br /&gt;
&lt;br /&gt;
==Rationale==&lt;br /&gt;
&lt;br /&gt;
The major portions of this specification were agreed by the Moodle Gradebook Working Group in June 2014.&lt;br /&gt;
&lt;br /&gt;
This work is supported by the results of the two surveys run by Moodle in May and June, as well as many bug reports in the tracker over the past few years.&lt;br /&gt;
&lt;br /&gt;
==Technology==&lt;br /&gt;
&lt;br /&gt;
* Compatible and maintainable: Javascript is required in this interface, hence our YUI library must be used wherever possible.&lt;br /&gt;
* Accessible: WCAG 2.0 compliance and ARIA implementation that is as complete as possible.&lt;br /&gt;
* Responsive: Must work well on all platforms from smartphone browsers up to large desktop screens.&lt;br /&gt;
&lt;br /&gt;
==Main display==&lt;br /&gt;
&lt;br /&gt;
The main display is the &amp;quot;scrolling spreadsheet&amp;quot; showing users as rows and activities as columns.&lt;br /&gt;
&lt;br /&gt;
We agreed to base this interface around the prototype from UCLA, which uses YUI:&lt;br /&gt;
&lt;br /&gt;
[[Image:UCLAgraderproto.png]]&lt;br /&gt;
&lt;br /&gt;
Final features include (some are in the above prototype *):&lt;br /&gt;
* Uses whole window (blocks can be collapsed/restored easily) *&lt;br /&gt;
* Scrolls up/down and left/right based on page scrolling *&lt;br /&gt;
* Display header rows for weight, range and average. &lt;br /&gt;
* Headers on top are sticky to the top of the viewport *&lt;br /&gt;
* Headers on left and sticky to the left of the viewport *&lt;br /&gt;
* Headers on bottom are sticky to the bottom of the viewport *&lt;br /&gt;
* Minimal cell size&lt;br /&gt;
* Endless scrolling - no paging&lt;br /&gt;
* Sort on any column *&lt;br /&gt;
* Collapse/expand columns and header rows (eg like Google sheets)&lt;br /&gt;
* Switch between categories / course columns or show only item columns&lt;br /&gt;
* Column with Last modified date for sorting users&lt;br /&gt;
* Wrap headers according to user-defined width (drag column borders?)&lt;br /&gt;
* Navigate between cells using arrow keys&lt;br /&gt;
&lt;br /&gt;
This display also offers some editing:&lt;br /&gt;
* Cells can be edited as now.&lt;br /&gt;
* Drag and drop columns to change order or put them into other categories&lt;br /&gt;
* Clear overrides button top of each column&lt;br /&gt;
&lt;br /&gt;
==Dynamic filters==&lt;br /&gt;
&lt;br /&gt;
Dynamic filtering controls at the top of the page can reduce the rows shown:&lt;br /&gt;
* by name search&lt;br /&gt;
* by group or groupings&lt;br /&gt;
* by grade range&lt;br /&gt;
* what else?&lt;br /&gt;
&lt;br /&gt;
==Single row/column editing==&lt;br /&gt;
&lt;br /&gt;
Each student row will have a link to a new page where all the grades for that student are shown in a long form (along with other settings like overrides) and can be edited. &lt;br /&gt;
&lt;br /&gt;
Each activity column will have a link to a new page where all the grades for that activity are shown (along with other settings) and can be edited.&lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
* Jump/swipe to next/previous row/column.&lt;br /&gt;
* For each cell in a row, jump to corresponding column by clicking near activity name, and for each cell in a column, jump to corresponding row by clicking near student name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Quickedit screens from LSU:&lt;br /&gt;
&lt;br /&gt;
One student:&lt;br /&gt;
[[File:rowedit.png]]&lt;br /&gt;
&lt;br /&gt;
One activity:&lt;br /&gt;
[[File:columnedit.png]]&lt;br /&gt;
&lt;br /&gt;
==Original workshop notes==&lt;br /&gt;
&lt;br /&gt;
Content&lt;br /&gt;
&lt;br /&gt;
    Datatable with activities columns, user rows (like UCLA)&lt;br /&gt;
    Range and Average along top below header row (Luther College)&lt;br /&gt;
        Use case for keeping average (on by default)? Many teachers like it. But averages is a load issue on large courses.&lt;br /&gt;
            Should averages be for course or just displayed? Some like the average to just be for the information displayed, but need to indicate that to the user.&lt;br /&gt;
            Table decision until later.&lt;br /&gt;
            Can freeze footer row to bottom of page to keep averages on-screen all the time (like UCLA)&lt;br /&gt;
        Currently includes 0 or empty scores and non-active enrollments (config option?)&lt;br /&gt;
&lt;br /&gt;
Dynamic Filtering&lt;br /&gt;
&lt;br /&gt;
    Any user field (as ELIS example) https://github.com/remotelearner/elis&lt;br /&gt;
    Groups and groupings&lt;br /&gt;
    Modified date ranges&lt;br /&gt;
&lt;br /&gt;
Clean responsive design&lt;br /&gt;
&lt;br /&gt;
    Smaller cells (eg: UCSB report)&lt;br /&gt;
    Fixed student information columns and header rows, not scrolling off page on vertical scroll (As UCLA example)&lt;br /&gt;
    Maximize content button to hide all blocks/headers (see UMN, Tracker)&lt;br /&gt;
    Mobile: for very smallest screens don’t even show table, just filters for users/activities -&amp;gt; list of names -&amp;gt; quickedit&lt;br /&gt;
&lt;br /&gt;
Columns&lt;br /&gt;
&lt;br /&gt;
    Drag and drop edges to resize widths&lt;br /&gt;
    Drag and drop columns to&lt;br /&gt;
        Change order&lt;br /&gt;
        Move them into (other) categories&lt;br /&gt;
        Save sort order and category movement in the backend&lt;br /&gt;
    Collapse/expand columns (eg Google sheets)&lt;br /&gt;
    Switch between categories / course columns or show only item columns&lt;br /&gt;
    Clear overrides button top of each column&lt;br /&gt;
    Teacher-definable columns for text. Add a grade, ability to assign text value to the GRADE (not just feedback)&lt;br /&gt;
    Last modified date - for sorting users&lt;br /&gt;
    Header cells&lt;br /&gt;
        Wrapped text to user-defined width&lt;br /&gt;
        Real weight displayed in cell (ex: &#039;W=28.33‰&#039;)&lt;br /&gt;
&lt;br /&gt;
Input&lt;br /&gt;
&lt;br /&gt;
    By admin setting, disable ability to input values into category and course cells. Disable would be the default setting.&lt;br /&gt;
    Ability to enter grades as points, letters or percentages. Letters would be translated to one point lower than the minimum for the next highest letter&lt;br /&gt;
    Links to single row/column edit forms (aka Quickedit from LSU)&lt;br /&gt;
        Quick Edit - add configuration option to specify which user fields are displayed for student&lt;br /&gt;
    Autofill column’s empty cells with selected value&lt;br /&gt;
&lt;br /&gt;
Redesign the control buttons for each cell. Let&#039;s just give this some thought how it could be substantially improved. Maybe a control drop down, edit, unhide, etc like some of the themes treat activity controls&lt;br /&gt;
&lt;br /&gt;
Admin setting controlled link to quick dump (preconfigured export to csv) (Luther College)&lt;br /&gt;
&lt;br /&gt;
Notifications/History&lt;br /&gt;
&lt;br /&gt;
    Like Google Docs tells you what/who changed something recently.&lt;br /&gt;
    Maybe color changed background for recently changed grades.&lt;br /&gt;
    Idea, when hovering over grade cells, indicate who made last change.&lt;br /&gt;
    Advisory that someone else is editing the gradebook&lt;br /&gt;
&lt;br /&gt;
Sandbox/”Unit tests”&lt;br /&gt;
&lt;br /&gt;
    Allow instructor to “test” their gradebook setup with sample data to ensure they have it setup correctly.&lt;br /&gt;
        LSU’s “Projected Final Grade” report allows students to see what they need to score on the remaining un-graded items.&lt;br /&gt;
            Can be expanded for instructors? Yes.&lt;br /&gt;
            Can it be turned off? Faculty can turn it on or off for students.&lt;br /&gt;
        Have a “Potholes” (UCSB) like dashboard to alert instructor of any potential problems with their gradebook.&lt;br /&gt;
&lt;br /&gt;
Arrow key support&lt;br /&gt;
&lt;br /&gt;
    Can already use tab and tab ordering works fine by going to next value in column.&lt;br /&gt;
    Idea: What about using arrow keys to move between columns or cells as well? (Remote Learner)&lt;br /&gt;
&lt;br /&gt;
Gradebook setup&lt;br /&gt;
&lt;br /&gt;
    Allow drag and dropping of items to reorder items/categories.&lt;br /&gt;
&lt;br /&gt;
Gradebook Help&lt;br /&gt;
&lt;br /&gt;
    Sliding screen as in UCLA example&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_Workplace_4.1_release_notes&amp;diff=64589</id>
		<title>Moodle Workplace 4.1 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_Workplace_4.1_release_notes&amp;diff=64589"/>
		<updated>2025-02-12T05:20:14Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=4.1=&lt;br /&gt;
See our [https://docs.moodle.org/401/en/Moodle_Workplace_new_features Moodle Workplace 4.1 new features page] in the user documentation for an introduction to Moodle Workplace 4.1 with screenshots. &lt;br /&gt;
==Major features==&lt;br /&gt;
Moodle Workplace 4.1 is based on top of Moodle LMS 4.1 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace:&lt;br /&gt;
* &#039;&#039;&#039;Advanced tenant appearance settings&#039;&#039;&#039;: tenant branding now includes two more settings that were available in Workplace 3.11: Navigation bar and Primary button colours. We have added more granularity to the permissions to change the appearance of the tenant, so advanced settings such as custom SCSS can be restricted to specific roles.&lt;br /&gt;
* &#039;&#039;&#039;Improvement to Tenant-allocation rules in the Shared Space&#039;&#039;&#039;. We have added two new conditions (“Users is allocated to tenant” and “User is not allocated to tenant”) and one action (“Allocate to tenant”) to Shared Dynamic Rules, with this addition we simplify the tenant allocation workflows for Admins in multi-tenant Workplace sites.&lt;br /&gt;
* &#039;&#039;&#039;Migration of core_reportbuilder custom reports&#039;&#039;&#039;. Migration feature now supports import and export of Custom Reports using Moodle LMS native report sources.&lt;br /&gt;
* &#039;&#039;&#039;Improved My Teams support in the Workplace App&#039;&#039;&#039;. The new My Teams page now includes information about learning and tracking in the Workplace App. &lt;br /&gt;
=== Other interesting features ===&lt;br /&gt;
* Hide/mask description of Dynamic rules conditions and actions when current user is not able to edit them&lt;br /&gt;
* Improved how hidden courses are displayed in the My Courses and Program pages&lt;br /&gt;
* Added &amp;quot;department&amp;quot; to User profile field condition in Dynamic Rules&lt;br /&gt;
* New setting to disable Program Cover page&lt;br /&gt;
* New setting to hide &amp;quot;Dates&amp;quot; section in the course information popup&lt;br /&gt;
* Fixed bug with deleted appointments being listed in user calendar&lt;br /&gt;
* Archive course certificates during program reset&lt;br /&gt;
* Display a warning when changing a tab without saving a form&lt;br /&gt;
* Allow tenant admin to edit locked profile fields for users in their tenant&lt;br /&gt;
* Fixed a bug causing an exception when viewing program progress report as an organisation manager after program import&lt;br /&gt;
== Upgrade notes for 4.1 ==&lt;br /&gt;
=== Upgrade from LMS ===&lt;br /&gt;
If &amp;quot;$CFG-&amp;gt;forcewpsetup = true;&amp;quot; is set in config.php before upgrading Moodle LMS to Moodle Workplace 4.1, the upgrade process add ‘myinprogress’ and ‘myavailable’ blocks to the default dashboard, and reset the dashboard for all users.&lt;br /&gt;
=== Upgrade from Moodle Workplace 3.11 and 4.0 ===&lt;br /&gt;
On upgrade from Workplace 3.11 to 4.1 in one step, all appearance settings will be preserved excepting the Drawer colour, which doesn’t have any equivalent in 4.1.&lt;br /&gt;
&lt;br /&gt;
Note that in case the upgrade is performed in two steps (3.11 &amp;gt; 4.0 and 4.0 &amp;gt; 4.1), the Navigation bar and Primary button colours will not be preserved in the corresponding settings, but the values of the settings that were added as custom CSS on upgrade to 4.0 will still be available (see [[Moodle Workplace 4.0 release notes#Branding|Workplace 4.0 upgrade notes]]).&lt;br /&gt;
=== Deprecation ===&lt;br /&gt;
We have deprecated the following in 4.1:&lt;br /&gt;
* get_managed_users web and get_teams_tab_filters web service in tool_organisation; &lt;br /&gt;
* get_user_learning_statuses in tool_program.&lt;br /&gt;
* tool_wp/db class&lt;br /&gt;
=4.1.1=&lt;br /&gt;
Moodle Workplace 4.1.1 is based on top of Moodle LMS 4.1.1 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace. This is a very short release as we launched 4.1 one week ago, so it does only include a couple of minor bug fixes.&lt;br /&gt;
=== Interesting features and fixes ===&lt;br /&gt;
* Fixed bug blocking users without the capability to edit their own profile to access Program Pages&lt;br /&gt;
=4.1.2=&lt;br /&gt;
See our [https://docs.moodle.org/401/en/Moodle_Workplace_new_features#4.1.2 Moodle Workplace 4.1.2 new features page] in the user documentation for an introduction to Moodle Workplace 4.1.2 with screenshots. &lt;br /&gt;
==Major features==&lt;br /&gt;
Moodle Workplace 4.1.2 is based on top of Moodle LMS 4.1.2 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace:&lt;br /&gt;
=== Key highlights ===&lt;br /&gt;
&#039;&#039;(Available in 4.1.2 rolling only)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Search, filtering and reporting improvements to the Team overview block&#039;&#039;&#039;:&lt;br /&gt;
** Quick filters that allow users to sort and filter data quickly within the Team overview block, making it easier to find the information they need.&lt;br /&gt;
** Access to full progress reports for certification, program, and course reports provide a comprehensive overview of each team member&#039;s learning progress&lt;br /&gt;
** Live search functionality that allows users to search for specific items in real-time within the Team overview block&lt;br /&gt;
** Warnings for overdue learning to provide notifications and reminders to users when they are falling behind on their coursework or certifications.&lt;br /&gt;
* &#039;&#039;&#039;Automatic branding enhancement for tenants&#039;&#039;&#039;: generate shades of grey automatically based on the tenant primary colour, to reinforce the brand identity while avoiding disturbing the experience.&lt;br /&gt;
* &#039;&#039;&#039;Improvements in Appointments:&#039;&#039;&#039;&lt;br /&gt;
** New expandable UI for session details and bookings, with consistent navigation and design across activity modules.&lt;br /&gt;
** New completion criteria based on attendance&lt;br /&gt;
* &#039;&#039;&#039;Improvements in Dynamic Rules&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;New action to end jobs&#039;&#039;&#039;&lt;br /&gt;
** &#039;&#039;&#039;New action to assign users to learning plans&#039;&#039;&#039;&lt;br /&gt;
** Option to suspend user&#039;s allocation to programs and certifications&lt;br /&gt;
* &#039;&#039;&#039;New setting to lock shared department and position frameworks&#039;&#039;&#039;: only users with appropriate permissions can manage jobs within locked departments and position frameworks.&lt;br /&gt;
* &#039;&#039;&#039;Apply only allowed filters in Certificates:&#039;&#039;&#039; new feature for users to define allowed filters for certificates, so that only the ones specified by the user are applied to the PDF content.&lt;br /&gt;
=== Other improvements ===&lt;br /&gt;
&#039;&#039;(Available in 4.1.2 rolling only)&#039;&#039;&lt;br /&gt;
* Lock the Audience tab in Custom Pages and don’t include audiences in duplication of custom pages for users with no permission to locked departments and positions.&lt;br /&gt;
* Added back a link to Moodle LMS&#039;s user management page in Site Administration&lt;br /&gt;
* Maintain the order of blocks in courses when switching from Workplace List to topics course format during upgrade&lt;br /&gt;
* Introduce new data attributes to distinguish the tenant for better tenant customization&lt;br /&gt;
* Preserve the URL when switching tenants&lt;br /&gt;
=== Other interesting features and fixes ===&lt;br /&gt;
&#039;&#039;(Available in 4.1.2 rolling and 4.1.2 standard)&#039;&#039;&lt;br /&gt;
* Add the possibility for Certificate element plugins to have their own settings page&lt;br /&gt;
* Add course name to “My Certificates” list&lt;br /&gt;
* Fixed a bug that prevented the import of positions and departments into existing frameworks, preserving the hierarchy&lt;br /&gt;
* Fixed a bug where the completion status for courses was not displaying correctly on the Program Page&lt;br /&gt;
* Fixed a bug that prevented tenant administrators from viewing hidden user fields&lt;br /&gt;
* Legacy custom reports can no longer be created if custom reports are disabled site wide&lt;br /&gt;
== Upgrade notes for 4.1.2 ==&lt;br /&gt;
=== Block order is preserved when upgrading to 4.1 rolling only ===&lt;br /&gt;
In Workplace 4.0, the old Workplace List course format was replaced with topics course format (more details on [[Moodle Workplace 4.0 release notes#Course%20format%20.E2.80.9CWPList.E2.80.9D|Workplace 4.0 upgrade notes]]). As a consequence of that upgrade, order of blocks in course page might not be preserved (as per MDL-37240).&lt;br /&gt;
&lt;br /&gt;
If the order of the blocks in courses has been changed and needs to be preserved, please make sure to upgrade to 4.1.2 rolling.&lt;br /&gt;
=== New data attributes to identify the tenant ===&lt;br /&gt;
Workplace 4.1.2 (rolling only) includes two new HTML data attributes to help to customize the styles for specific tenants. The new attributes are &amp;lt;code&amp;gt;[data-tenantid=&amp;quot;{tenant_id}&amp;quot;]&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;[data-tenantidnumber=&amp;quot;{tenant_idnumber}&amp;quot;]&amp;lt;/code&amp;gt; (available when &amp;lt;code&amp;gt;idnumber&amp;lt;/code&amp;gt; is defined for the tenant)&lt;br /&gt;
=4.1.3=&lt;br /&gt;
See our [https://docs.moodle.org/401/en/Moodle_Workplace_new_features#4.1.3 Moodle Workplace 4.1.3 new features page] in the user documentation for an introduction to Moodle Workplace 4.1.3 with screenshots. &lt;br /&gt;
==Major features==&lt;br /&gt;
Moodle Workplace 4.1.3 is based on top of Moodle LMS 4.1.3 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace:&lt;br /&gt;
=== Key highlights ===&lt;br /&gt;
&#039;&#039;(Available in 4.1.3 rolling only)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Support contact by tenant.&#039;&#039;&#039; Now it is possible to configure the support contact information (support contact, support URL and availability) at a tenant level, so different tenant can have their own support contact settings.&lt;br /&gt;
* T&#039;&#039;&#039;eam’s overdue learning warnings for managers&#039;&#039;&#039;. The team overview block in the My Teams page now displays a warning when there are people with overdue learning to their managers. This notice includes a link to the corresponding report.&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;&#039;User first login dynamic rule condition.&#039;&#039;&#039;&#039;&#039;&#039; Now it’s possible to create automations based on user’s first login.&lt;br /&gt;
=== Other improvements ===&lt;br /&gt;
&#039;&#039;(Available in 4.1.3 rolling only)&#039;&#039;&lt;br /&gt;
* Notify program creators when a course in the program when course completion is not set for courses with completion tracking enabled&lt;br /&gt;
* Add manager and department lead permissions to CSV import&lt;br /&gt;
=== Other interesting features and fixes ===&lt;br /&gt;
&#039;&#039;(Available in 4.1.3 rolling, 4.1.3 standard and 4.0.8)&#039;&#039;&lt;br /&gt;
* Fixed a bug causing appointment sessions being deleted after deleting another session.&lt;br /&gt;
* Fixed a bug that prevented assigning jobs in the upload user tool when using positions with duplicated idnumbers&lt;br /&gt;
* Fixed a bug in causing ad-hoc reports scheduled to be stuck endlessly&lt;br /&gt;
== Upgrade notes for 4.1.3 ==&lt;br /&gt;
Due to a fixed bug, the reports generated in the scheduled reports may now contain more data than they did before. We recommend reviewing your schedules and make sure that &amp;quot;View report as&amp;quot; is correct. For example, if the &amp;quot;View report as&amp;quot; is a global admin, the reports may contain cross-tenant data and they will be sent to all users in the schedules audiences, even those who do not normally have access to cross-tenant data.&lt;br /&gt;
= 4.1.4 =&lt;br /&gt;
Moodle Workplace 4.1.4 is based on top of Moodle LMS 4.1.4 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Interesting features and bug fixes ===&lt;br /&gt;
* Fixed a bug where the &#039;reset program&#039; option was incorrectly displayed for dynamic allocation&lt;br /&gt;
* Fixed a bug in the &#039;Access&#039; tab on tenant page where some users might have been incorrectly displayed.&lt;br /&gt;
* Fixed a bug during the upgrade process that caused it to get stuck in a loop&lt;br /&gt;
* Fixed a bug during the installation process that caused blocks in the dashboard to be copied multiple times under certain circumstances.&lt;br /&gt;
* Fixed a bug in tenant archiving that was granting tenant administration permissions from the default tenant to the tenant administrator of the archived tenant&lt;br /&gt;
* Fixed a bug during the upgrade process that caused it to get stuck in a loop (&#039;&#039;4.1.4 rolling only)&#039;&#039;&lt;br /&gt;
= 4.1.5 =&lt;br /&gt;
Moodle Workplace 4.1.5 is based on top of Moodle LMS 4.1.5 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Highlights ===&lt;br /&gt;
* We added some changes to the &amp;quot;Workplace&amp;quot; theme that allow to create child themes easier. We have released an example &amp;quot;[https://github.com/moodleworkplace/moodle-theme_wpchild Workplace child theme]&amp;quot; &lt;br /&gt;
* Moved &amp;quot;Information&amp;quot; tab to the second position on the course page&lt;br /&gt;
* Changed report data source &amp;quot;Issued certificates&amp;quot; removing a very strict capability check. Now it is possible to create reports such as &amp;quot;My certificates&amp;quot; or &amp;quot;My team&#039;s certificates&amp;quot; that can be accessed by users who can not view the templates list.&lt;br /&gt;
** &#039;&#039;&#039;Upgrade notes:&#039;&#039;&#039; To prevent accidental disclosure of new data to people who already have reports using the &amp;quot;Issued certificates&amp;quot; datasource, we have added a new condition that mimics the previous hardcoded restriction. This condition (called &amp;quot;Permission to access templates&amp;quot;) is automatically added during upgrade to all existing reports from this datasource. It can be removed if necessary. This condition will not be automatically added to the newly created reports but can be added manually if needed.&lt;br /&gt;
=== Other fixes ===&lt;br /&gt;
* Fixed a bug causing program reset ad-hoc task to fail&lt;br /&gt;
* Fixed a bug insufficiently resetting course module views during program reset &lt;br /&gt;
* Fixed a bug causing failures during organisation structure export&lt;br /&gt;
* Improved Dynamic rules, allowing some actions to be executed as scheduled tasks only. Changed actions &amp;quot;Assign to learning plans&amp;quot; and respective &amp;quot;Unassign&amp;quot; action to use this functionality, because they can fail if they are executed in a session of a student&lt;br /&gt;
* Changed workplace activity icons to look more consistent with the LMS activity icons (white instead of black)&lt;br /&gt;
* Bug fixes and improvements in how some tenant configuration data is being sent to the mobile app (among other things, this makes sure that the site name in the user information page is correct and corresponds to the current tenant).&lt;br /&gt;
* Added validation to the tenant branding &amp;quot;Custom SCSS&amp;quot; field to prevent accidental breaking of the whole site layout&lt;br /&gt;
* Added column &amp;quot;Session date &amp;amp; time&amp;quot; to Appointments datasources that was present in legacy report builder in 3.11 but was forgotten in 4.0+ report builder&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This version also contains a fix for a security issue in Moodle Workplace, the details will be communicated to the Moodle Partners on the day of release and disclosed here later.&lt;br /&gt;
= 4.1.6 =&lt;br /&gt;
Moodle Workplace 4.1.6 is based on top of Moodle LMS 4.1.6 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Other fixes ===&lt;br /&gt;
* Fixed: Suspended on Program report displays &amp;quot;Yes&amp;quot; even though user is not suspended from program&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This version also contains a fix for a security issue in Moodle Workplace, the details will be communicated to the Moodle Partners on the day of release and disclosed here later.&lt;br /&gt;
= 4.1.7 =&lt;br /&gt;
Moodle Workplace 4.1.7 is based on top of Moodle LMS 4.1.7 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
* Fixed condition &#039;Select course&#039; in the course participants custom report&lt;br /&gt;
* Appointment status and session summary no longer shows Wait-listed users as &#039;Booked&#039;&lt;br /&gt;
* Allow to sort by allocation date column in report builder&lt;br /&gt;
* Fixed bug when manually changing certification due date causes date to get stuck on program info card&lt;br /&gt;
* Do not show percentage in recent courses block if course does not have completion&lt;br /&gt;
* It is now possible to delete user profile picture in the tenant user editing popup&lt;br /&gt;
* Do not show the enable/disable switch for the manual auth method that can never be disabled&lt;br /&gt;
= 4.1.8 =&lt;br /&gt;
Moodle Workplace 4.1.8 is based on top of Moodle LMS 4.1.8 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
* Removed and empty link in the &amp;quot;Certification progress&amp;quot; report&lt;br /&gt;
&lt;br /&gt;
= 4.1.9 =&lt;br /&gt;
Moodle Workplace 4.1.9 is based on top of Moodle LMS 4.1.9 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
* Corrected the link to the user documentation in the Course Certificate activity module&lt;br /&gt;
* Fixed a bug in the Course Certificate scheduled task related with deleted templates&lt;br /&gt;
&lt;br /&gt;
= 4.1.10 =&lt;br /&gt;
Moodle Workplace 4.1.10 is based on top of Moodle LMS 4.1.10 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
&lt;br /&gt;
* Fixed multiple accessibility issues in several components in the scope of the WCAG 2.1 AA accreditation&lt;br /&gt;
&lt;br /&gt;
= 4.1.11 =&lt;br /&gt;
Moodle Workplace 4.1.11 is based on top of Moodle LMS 4.1.11 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
&lt;br /&gt;
* Various accessibility fixes related to the ongoing effort to achieve WCAG AA accessibility accreditation for Moodle Workplace&lt;br /&gt;
&lt;br /&gt;
= 4.1.12 =&lt;br /&gt;
Moodle Workplace 4.1.12 is based on top of Moodle LMS 4.1.12 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
&lt;br /&gt;
* Add support for separate group mode to Appointments activity module&lt;br /&gt;
&lt;br /&gt;
=4.1.13=&lt;br /&gt;
Moodle Workplace 4.1.13 is based on top of Moodle LMS 4.1.13 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
&lt;br /&gt;
=== Security fixes ===&lt;br /&gt;
* A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
= 4.1.14 =&lt;br /&gt;
Moodle Workplace 4.1.14 is based on top of Moodle LMS 4.1.14 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
&lt;br /&gt;
=== Security fixes ===&lt;br /&gt;
&lt;br /&gt;
* A number of security related issues were resolved&lt;br /&gt;
&lt;br /&gt;
= 4.1.15 =&lt;br /&gt;
Moodle Workplace 4.1.15 is based on top of Moodle LMS 4.1.15 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
&lt;br /&gt;
=== Fixes ===&lt;br /&gt;
&lt;br /&gt;
* Resolved issue where users from other tenants could be incorrectly displayed on the tag index page&lt;br /&gt;
&lt;br /&gt;
= 4.1.16 =&lt;br /&gt;
Moodle Workplace 4.1.16 is based on top of Moodle LMS 4.1.16 and has all the new features of the core version. In addition, it contains all exclusive features from Moodle Workplace.&lt;br /&gt;
&lt;br /&gt;
There were no workplace-specific fixes in this release.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Exporting/importing_several_question_categories_at_once&amp;diff=64579</id>
		<title>Exporting/importing several question categories at once</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Exporting/importing_several_question_categories_at_once&amp;diff=64579"/>
		<updated>2025-02-10T08:32:57Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The new interface, which lets you export several question categories at once. &lt;br /&gt;
&lt;br /&gt;
To activate the export / import multiple categories question, click &amp;quot;Write several&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[File:activate_mod.jpg]]&lt;br /&gt;
&lt;br /&gt;
After clicking &amp;quot;Write several&amp;quot; combobox list elements is replaced by a tree of categories as it shown on the picture.&lt;br /&gt;
&lt;br /&gt;
[[File:tree_categories.jpg]]&lt;br /&gt;
&lt;br /&gt;
How to change the interface is described below .&lt;br /&gt;
&lt;br /&gt;
1.	Category you want to export, are chosen as you can watch at the image. &lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:Capture.png]]&lt;br /&gt;
&lt;br /&gt;
To achieve the desired result, I have to use it.&lt;br /&gt;
&lt;br /&gt;
==Change export/import function and file structure==&lt;br /&gt;
&lt;br /&gt;
Import function does not need to be changed. Importing several question categories works correctly. &lt;br /&gt;
&lt;br /&gt;
Export function needs to be corrected. Now only one question category exported. &lt;br /&gt;
&lt;br /&gt;
Now Moodle has the structure of the file described below.&lt;br /&gt;
&lt;br /&gt;
In the file category describes then questions describes which belong to the category then next category describes etc. This structure of the file is suitable for export of several question categories. A structure can be represented visually as&lt;br /&gt;
&lt;br /&gt;
[Description category1]&lt;br /&gt;
&lt;br /&gt;
[Description first question of category1]&lt;br /&gt;
&lt;br /&gt;
[Description second question of category1]&lt;br /&gt;
&lt;br /&gt;
[Description third question of category1]&lt;br /&gt;
&lt;br /&gt;
[Description category2]&lt;br /&gt;
&lt;br /&gt;
[Description first question of category2]&lt;br /&gt;
&lt;br /&gt;
[Description second question of category2] .&lt;br /&gt;
&lt;br /&gt;
So to achieve the goal I will not have to change the structure of the file.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=64578</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=64578"/>
		<updated>2025-02-10T08:28:54Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Implemented&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=261660&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.8}}&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens.&lt;br /&gt;
&lt;br /&gt;
This report will be built on top of the new [[Events API]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines an event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we are using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== Subscribe to a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of the Event Monitor report where users can see a list of rules and their current subscriptions. This also lets users to subscribe to new rules or delete their current subscriptions.&lt;br /&gt;
&lt;br /&gt;
[[File:subscriptions.png]]&lt;br /&gt;
&lt;br /&gt;
==== Manage rules ====&lt;br /&gt;
&lt;br /&gt;
This page lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page will look like:-&lt;br /&gt;
&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
&lt;br /&gt;
One scenario may be that you wish to be notified when discussions are becoming active in a course&#039;s forums.&lt;br /&gt;
&lt;br /&gt;
The figure above shows the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor the &#039;Post Created&#039; event, which is triggered by the &#039;Forum&#039; module. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever 30 posts are created in 60 minutes in forums of a course, or within a single forum that have identified in their subscription to the rule. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
=== Message template ===&lt;br /&gt;
&lt;br /&gt;
One interesting option of rule addition is the message template. When creating or editing a rule, the user can embed placeholders to add details to notification messages. &lt;br /&gt;
&lt;br /&gt;
The use of placeholders in a message template is optional, so you don&#039;t have to use placeholders; you can use any personalised message.&lt;br /&gt;
&lt;br /&gt;
The following table lists the available placeholders that can be used in a message template.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Placeholder&lt;br /&gt;
! What it does?&lt;br /&gt;
! Example&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;{link}&#039;&#039;&#039;&lt;br /&gt;
| Direct link to the actual event, eg a forum discussion.&lt;br /&gt;
| http://YourMoodle.com/mod/forum/discuss.php?d=2&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;{modulelink}&#039;&#039;&#039;&lt;br /&gt;
| Link to the module where the event has happened, eg a forum&lt;br /&gt;
| http://YourMoodle.com/mod/forum/view.php?id=8&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;{rulename}&#039;&#039;&#039;&lt;br /&gt;
| A name for the rule.&lt;br /&gt;
| Student discussions&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;{description}&#039;&#039;&#039;&lt;br /&gt;
| A description of the rule.&lt;br /&gt;
| I want to receive notifications when there is a large volume of student posts in a discussion.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;{eventname}&#039;&#039;&#039;&lt;br /&gt;
| The name of the event being monitored.&lt;br /&gt;
| Forum post created.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
The examples above show the placeholders for a rule to monitor the &#039;&#039;&#039;Forum post created&#039;&#039;&#039; event. Here is an example of a message template using these placeholders.&lt;br /&gt;
&lt;br /&gt;
 The rule &#039;&#039;&#039;{rulename}&#039;&#039;&#039;, monitoring the event &#039;&#039;&#039;{eventname}&#039;&#039;&#039;, has just been fulfilled. &lt;br /&gt;
 Click the following link to go to the forum discussion: &#039;&#039;&#039;{link}&#039;&#039;&#039;&lt;br /&gt;
 Rule description: &#039;&#039;&#039;{description}&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The result of this message template would be as follows.&lt;br /&gt;
&lt;br /&gt;
 The rule Student discussions, monitoring the event Forum post created, has just been fulfilled. &lt;br /&gt;
 Click on the following link to go to the forum discussion: http://YourMoodle.com/mod/forum/discuss.php?d=2 .&lt;br /&gt;
 Rule description: I want to receive notifications when there are a large volume of student posts in a discussion.&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s create a rule called &#039;&#039;&#039;Glossary entries&#039;&#039;&#039; to monitor when a new glossary entry is created:&lt;br /&gt;
&lt;br /&gt;
 The rule &#039;&#039;&#039;{rulename}&#039;&#039;&#039;, monitoring the event &#039;&#039;&#039;{eventname}&#039;&#039;&#039;, has just been fulfilled. &lt;br /&gt;
 Click the following link to go to see the new entry created: &#039;&#039;&#039;{link}&#039;&#039;&#039;&lt;br /&gt;
 Rule description: &#039;&#039;&#039;{description}&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The result of this message template would be as follows.&lt;br /&gt;
&lt;br /&gt;
 The rule Glossary entries, monitoring the event Entry has been created, has just been fulfilled. &lt;br /&gt;
 Click on the following link to go to see the new entry created: http://YourMoodle.com/mod/glossary/view.php?id=5&amp;amp;mode=entry&amp;amp;hook=1.&lt;br /&gt;
 Rule description: I want to receive notifications when a new glossary entry is created.&lt;br /&gt;
&lt;br /&gt;
Note that some events do not have a link.  &#039;&#039;&#039;Course deleted&#039;&#039;&#039; and &#039;&#039;&#039;Course module deleted&#039;&#039;&#039; for example, would not display any link if &#039;&#039;&#039;{link}&#039;&#039;&#039; or &#039;&#039;&#039;{modulelink}&#039;&#039;&#039; is used.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* A notification can be sent straight to a user&#039;s mobile if there is a situation that needs immediate attention.&lt;br /&gt;
* The report will be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forums or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when new chapters are created in a book.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
* Send notification (to admin) when potential security risk might happen due to change in system setting.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
* Allow events to be subscribed by only certain roles&lt;br /&gt;
* Forced subscriptions for students for certain rules&lt;br /&gt;
* An activity stream for messages&lt;br /&gt;
* An facebook style notification system for notifying logged in users&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Events API]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site. (For further information refer to [[https://docs.moodle.org/dev/Task_API#Adhoc_task_usage Adhoc tasks]])&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Email_reminders_for_calendar_events&amp;diff=64577</id>
		<title>Email reminders for calendar events</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Email_reminders_for_calendar_events&amp;diff=64577"/>
		<updated>2025-02-10T08:24:53Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Reminders are very useful for both students as well as teachers to recall their scheduled event before the actual moment. This project is about creating a set of reminders for Moodle calendar events and sending them &#039;&#039;automatically&#039;&#039; to relevant users on timely manner via Moodle message interface. It will be implemented as a local plugin to the Moodle.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
Moodle 2.2 required&lt;br /&gt;
&lt;br /&gt;
== Community Bonding Period ==&lt;br /&gt;
&lt;br /&gt;
=== Milestones ===&lt;br /&gt;
# DONE - Refine the project proposal with Michael, Rossiani and the community&lt;br /&gt;
# DONE - Feature discussion&lt;br /&gt;
# DONE - Create mockups&lt;br /&gt;
&lt;br /&gt;
=== Features ===&lt;br /&gt;
Following features are expecting to package with the reminders plugin.&lt;br /&gt;
&lt;br /&gt;
:1. Reminders can be sent by customizing according to each event type.&lt;br /&gt;
::* Separate message providers for each event type.&lt;br /&gt;
::* Ability to customize message content according to event type.&lt;br /&gt;
:2. Administrator configurations&lt;br /&gt;
::* Administrator can enable/disable the process of sending reminders without uninstalling the plugin.&lt;br /&gt;
::* Ability to choose how many days ahead should the reminders be created &#039;&#039;for each event type&#039;&#039;.&lt;br /&gt;
::** Reminders can be created only by days.&lt;br /&gt;
::** Supported only fixed amount of days ahead such as 7 days, 3 days and 1 day.&lt;br /&gt;
::* Ability to keep/remove history of reminder events.&lt;br /&gt;
:2. User configurations&lt;br /&gt;
::* User can select desired method of receiving reminder notifications on each message provider.&lt;br /&gt;
&lt;br /&gt;
== Coding Period ==&lt;br /&gt;
&lt;br /&gt;
=== Milestones ===&lt;br /&gt;
&lt;br /&gt;
:1. DONE - Finalize the abstract architecture.&lt;br /&gt;
:2. DONE - Implementing the basic structure of the plugin. (CONTRIB-3648)&lt;br /&gt;
::* DONE - Creating a suitable version file.&lt;br /&gt;
::* DONE - Creating a language file.&lt;br /&gt;
::* DONE - Creating a message provider file.&lt;br /&gt;
::* DONE - Creating a lib file for the cron function.&lt;br /&gt;
:3. DONE - Implementing message providers for each event type. (CONTRIB-3659)&lt;br /&gt;
:4. DONE - Providing a administrator settings page. (CONTRIB-3660)&lt;br /&gt;
:5. DONE - Implementing necessary reminder classes. (CONTRIB-3669)&lt;br /&gt;
::* DONE - Creating abstract reminder class.&lt;br /&gt;
::* DONE - Creating concrete reminder classes for each event type.&lt;br /&gt;
:6. DONE - Building functionality.&lt;br /&gt;
::* DONE - Generation of message content for reminders. (CONTRIB-3671)&lt;br /&gt;
::* DONE - Implementation of Cron function. (CONTRIB-3670)&lt;br /&gt;
::* DONE - Extending to support plugin for repeated events. (CONTRIB-3672)&lt;br /&gt;
:7. IN PROGRESS - Testing&lt;br /&gt;
:8. IN PROGRESS - Bug fixing&lt;br /&gt;
&lt;br /&gt;
=== File Structure ===&lt;br /&gt;
Following shows expected file structure of the plugin. Plugin name would be &amp;quot;&#039;&#039;reminders&#039;&#039;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* contents/course_reminder.class.php&lt;br /&gt;
* contents/site_reminder.class.php&lt;br /&gt;
* contents/group_reminder.class.php&lt;br /&gt;
* contents/user_reminder.class.php&lt;br /&gt;
* contents/due_reminder.class.php&lt;br /&gt;
* db/access.php&lt;br /&gt;
* db/message.php&lt;br /&gt;
* db/upgrade.php&lt;br /&gt;
* lang/en/local_reminders.php&lt;br /&gt;
* reminder.class.php&lt;br /&gt;
* version.php&lt;br /&gt;
* lib.php&lt;br /&gt;
* settings.php&lt;br /&gt;
* README&lt;br /&gt;
&lt;br /&gt;
=== Explanation ===&lt;br /&gt;
Picking up relevant events to send reminders in advance is very important and critical. Reminders must be sent only once for a event on predefined ahead of days. Identifying such events has to be done efficiently and carefully. It shows below how it can be achieved.&lt;br /&gt;
&lt;br /&gt;
Events are checked against a &#039;&#039;fixed amount of time period&#039;&#039; in each and every cron cycle.&lt;br /&gt;
&lt;br /&gt;
If any of event is falling exactly 1, 3 or 7 days ahead for that checking time period, that event will be marked as&lt;br /&gt;
a ready event to send reminders. In mathematically, if any event should satisfy to send reminders &lt;br /&gt;
&lt;br /&gt;
        (t(Ei) - X &amp;gt; T1) AND (t(Ei) - X &amp;lt;= T2) AND (t(Ei) &amp;gt; T2)&lt;br /&gt;
&lt;br /&gt;
Where t(Ei) is the start time of the event and X is a set of constants indicates 1,3 or 7 days in seconds.&lt;br /&gt;
&lt;br /&gt;
That &#039;&#039;fixed amount of time period&#039;&#039; is decided as the timestamp different between last cron cycle (this timestamp is not the&lt;br /&gt;
timestamp corresponding to the start of that cron cycle, but the time it began to check for its previous timeslot. This&lt;br /&gt;
can be extracted from info field in log record) and current time.&lt;br /&gt;
&lt;br /&gt;
:1. If the running cron cycle is the first ever cron cycle (i.e. no log record could find for a previous cron cycle), then the time will be cutoff by X amount of days before as configured.&lt;br /&gt;
[[File:first_cron.jpg]]&lt;br /&gt;
&lt;br /&gt;
::* (t1,t2) is the time period the time period that cron is running.&lt;br /&gt;
::* (T1,T2) is the time period which will be checked against events. (T1-T2) will be a constant and will be used at most once.&lt;br /&gt;
&lt;br /&gt;
:2. Otherwise,&lt;br /&gt;
[[File:nth_cron.jpg]]&lt;br /&gt;
::* (t1,t2) is the interval between two cron cycles as defined in plugin.&lt;br /&gt;
::* (T1,T2) is the time inspecting region. (T1 will be decided by log record for the last cron cycle)&lt;br /&gt;
&lt;br /&gt;
=== High Level Architecture Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:overall_architecture.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Reminders Class Diagram ===&lt;br /&gt;
[[File:reminder_class_diagram_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Mockups ==&lt;br /&gt;
=== Administrator Setting Page ===&lt;br /&gt;
[[File:reminders_admin_config_page.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Message Format (HTML) ===&lt;br /&gt;
* Message Title : Reminder: ${event_detail} @ ${event_date_time}&lt;br /&gt;
&lt;br /&gt;
[[File:message_format_HTML.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Message Format (Plain-text) === &lt;br /&gt;
* Message Title : Reminder: ${event_detail} @ ${event_date_time}&lt;br /&gt;
* Message Content:&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;${message_title}&#039;&#039;&#039;&lt;br /&gt;
: Reminder - #n days remaining&lt;br /&gt;
&lt;br /&gt;
: When -&amp;gt; ${event_time}&lt;br /&gt;
: What -&amp;gt; ${event_course} or ${event_type}&lt;br /&gt;
: Description -&amp;gt; ${event_description}&lt;br /&gt;
&lt;br /&gt;
== Screenshots ==&lt;br /&gt;
=== Admin Settings Page ===&lt;br /&gt;
[[File:settings_page_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Sample e-mail reminder for course event ===&lt;br /&gt;
[[File:sample_email_reminder_course.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Sample e-mail reminder for due event ===&lt;br /&gt;
[[File:sample_email_reminder_due.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
* Mentors: [http://moodle.org/user/view.php?id=381842&amp;amp;course=5 Michael de Raadt] and [http://moodle.org/user/view.php?id=955449&amp;amp;course=5 Rossiani Wijaya]&lt;br /&gt;
* Special thanks goes to [http://moodle.org/user/profile.php?id=1297063 Luiggi Sansonetti] who translated the plugin into French language.&lt;br /&gt;
* Another thank goes to Guido Roessling for providing a German translation for this plugin&lt;br /&gt;
&lt;br /&gt;
== Tracker ==&lt;br /&gt;
* CONTRIB-3647 Automating Email reminders for calendar events&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* Plugin development [https://github.com/isuru89/moodle-reminders-for-calendar-events Repository]&lt;br /&gt;
* [https://docs.moodle.org/dev/Projects_for_new_developers Moodle - Google Summer of Code 2012 Idea List]&lt;br /&gt;
* [http://www.google-melange.com/gsoc/proposal/review/google/gsoc2012/isuru89/1 Original Proposal - GSoC 2012]&lt;br /&gt;
* RSS Feed from Personal Blog, [http://uisurumadushanka89.blogspot.com/feeds/posts/default/-/gsoc RSS Feed].&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Email_notification_when_a_quiz_is_submitted&amp;diff=64576</id>
		<title>Email notification when a quiz is submitted</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Email_notification_when_a_quiz_is_submitted&amp;diff=64576"/>
		<updated>2025-02-10T08:24:17Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
This is a old feature request ([http://tracker.moodle.org/browse/MDL-648 MDL-648]) and there are various patches floating around, but I now want to implement this properly in core, probably for Moodle 2.0, but maybe for Moodle 1.9 if we are lucky.--[[User:Tim Hunt|Tim Hunt]] 04:59, 21 June 2007 (CDT)&lt;br /&gt;
&lt;br /&gt;
[http://moodle.org/mod/forum/discuss.php?d=74185 Please discuss this proposal in this forum thread].&lt;br /&gt;
&lt;br /&gt;
==Brief description of the requirement==&lt;br /&gt;
&lt;br /&gt;
When a student clicks &#039;Submit all and finish&#039; on a quiz attempt, send an email confirmation to one or both of:&lt;br /&gt;
* The student themselves.&lt;br /&gt;
* Any designated 3rd parties - who gets emailed needs to take account of the &#039;Separate groups&#039; setting, if appropriate.&lt;br /&gt;
&lt;br /&gt;
It should be possible for admins to customise the text of either of these emails.&lt;br /&gt;
&lt;br /&gt;
==Design==&lt;br /&gt;
&lt;br /&gt;
===Controlling who gets emailed===&lt;br /&gt;
&lt;br /&gt;
Users will get an email confirmation of their own quiz submission if they have the mod/quiz:emailconfirmsubmission capability on the quiz. (This means that whether confirmations are sent can be controlled for the whole site by changing the role definition, and it can be separately controlled for each quiz using role overrides.)&lt;br /&gt;
&lt;br /&gt;
Similarly, users will get notified of other people submissions if they have the mod/quiz:emailnotifysubmission capability. If a user has both mod/quiz:emailconfirmsubmission and  mod/quiz:emailnotifysubmission then they only get one email, the confirmsubmission one.&lt;br /&gt;
&lt;br /&gt;
====Interaction with groups mode====&lt;br /&gt;
&lt;br /&gt;
If the quiz is set to &#039;Separate groups&#039;, then the notifysubmission email will only be sent to those users who are in the same group as the person who submitted, or who have the moodle/site:accessallgroups capability.&lt;br /&gt;
&lt;br /&gt;
===Configuring the text of the emails===&lt;br /&gt;
&lt;br /&gt;
The emails will be stored in language strings in the quiz.php lang file. There will be strings emailconfirmsubject, emailconfirmbody, emailnotifysubject and emailnotifybody.&lt;br /&gt;
&lt;br /&gt;
When these strings are loaded, a &#039;$a&#039; variable contining lots of useful information will be passed in which may be used in the message. The fields available will be:&lt;br /&gt;
&lt;br /&gt;
;$a-&amp;gt;coursename&lt;br /&gt;
:The name of the course&lt;br /&gt;
;$a-&amp;gt;courseshortname&lt;br /&gt;
:The shortname of the course&lt;br /&gt;
;$a-&amp;gt;quizname&lt;br /&gt;
:The name of the quiz&lt;br /&gt;
;$a-&amp;gt;quizreporturl&lt;br /&gt;
:The URL of the results overview for this quiz (.../mod/quiz/report.php?q=&#039;&#039;quizid&#039;&#039;)&lt;br /&gt;
;$a-&amp;gt;quizreportlink&lt;br /&gt;
:The URL of the results overview URL and quiz name as a HTML link&lt;br /&gt;
;$a-&amp;gt;quizreviewurl&lt;br /&gt;
:The URL of the review page for this attempt (.../mod/quiz/review.php?attempt=&#039;&#039;attemptid&#039;&#039;)&lt;br /&gt;
;$a-&amp;gt;quizreviewlink&lt;br /&gt;
:The attempt review URL and quiz name as a HTML link&lt;br /&gt;
;$a-&amp;gt;quizurl&lt;br /&gt;
:The URL of the main page of the quiz (.../mod/quiz/view.php?q=&#039;&#039;quizid&#039;&#039;)&lt;br /&gt;
;$a-&amp;gt;quizlink&lt;br /&gt;
:The URL of the quiz and the quiz name as a HTML link&lt;br /&gt;
;$a-&amp;gt;attemptsubmissiontime&lt;br /&gt;
:The time the attempt was submitted, formatted using userdate().&lt;br /&gt;
;$a-&amp;gt;timetaken&lt;br /&gt;
:How long the quiz attempt lasted.&lt;br /&gt;
;$a-&amp;gt;studentname&lt;br /&gt;
:The name of the person who submitted the quiz.&lt;br /&gt;
;$a-&amp;gt;studentidnumber&lt;br /&gt;
:The idnumber of the person who submitted the quiz.&lt;br /&gt;
;$a-&amp;gt;studentusername&lt;br /&gt;
:The username of the person who submitted the quiz.&lt;br /&gt;
;$a-&amp;gt;username&lt;br /&gt;
:The name of the user the email is being sent to.&lt;br /&gt;
;$a-&amp;gt;useridnumber&lt;br /&gt;
:The idnumber of the person who submitted the quiz.&lt;br /&gt;
;$a-&amp;gt;userusername&lt;br /&gt;
:The username of the user the email is being sent to.&lt;br /&gt;
&lt;br /&gt;
===When the emails are sent===&lt;br /&gt;
&lt;br /&gt;
It is important that if an error occurs during sending of the emails, then this does not prevent the quiz from being submitted. So we will use the [[Events API]] to fire an event when the quiz is submitted, and then write an event handler to do the email sending.&lt;br /&gt;
&lt;br /&gt;
==Where to implement this==&lt;br /&gt;
&lt;br /&gt;
Graham Miller volunteered in the forums to try to implement this, so here are some brief notes on how.&lt;br /&gt;
&lt;br /&gt;
===Which version?===&lt;br /&gt;
&lt;br /&gt;
Since this is a new feature, it really ought to go into HEAD. However, if we took out the use of the events API, it could be done in essentially the same way in the 1.8 and 1.7 branches and HEAD. That would be OK for a first implementation.&lt;br /&gt;
&lt;br /&gt;
===Where should the code go===&lt;br /&gt;
&lt;br /&gt;
In /mod/quiz/locallib.php, we need a new quiz_send_notification_emails(...) function to do the work. More on this in a moment.&lt;br /&gt;
&lt;br /&gt;
This new function should then be called from /mod/quiz/attempt.php. Pass in as much as possible if the information that is already available in attemtp.php as function arguments, so we don&#039;t have to re-fetch it from the database. The call should be just before the bit&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/// Check access to quiz page&lt;br /&gt;
&lt;br /&gt;
    // ... [SNIP]&lt;br /&gt;
&lt;br /&gt;
    if ($finishattempt) {&lt;br /&gt;
        redirect(&#039;review.php?attempt=&#039;.$attempt-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The new capabilities need to be added to /mod/quiz/db/access.php as usual, with a bump of the version number in /mod/quiz/db/version.php.&lt;br /&gt;
&lt;br /&gt;
To test whether to send to the student who has just submitted, use has_capability. To get a list of 3rd parties to email, user get_users_by_capability, passing $doanything = false.&lt;br /&gt;
&lt;br /&gt;
To prepare the $a variable, you mostly just need to assemble the right data from the users, quiz and course. For the bits relating to attempts (that is, how to format the times), you can see the code necessary in review.php.&lt;br /&gt;
&lt;br /&gt;
Then you use get_string to generate the email body and subject.&lt;br /&gt;
&lt;br /&gt;
Then you use email_to_user from from lib/moodlelib.php to send the email.&lt;br /&gt;
&lt;br /&gt;
Obviously you need to do deal with any errors that may arise along the way. (The main benefit of using the events api would have been easier error handling.)&lt;br /&gt;
&lt;br /&gt;
Finally, write some teacher-facing documentation at an appropriate place on this wiki.&lt;br /&gt;
&lt;br /&gt;
==Examples of the type of email messages people might want to send==&lt;br /&gt;
&lt;br /&gt;
===OU OpenMark system===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Subject: OU online assessment confirmation - $a-&amp;gt;quizname&lt;br /&gt;
&lt;br /&gt;
Thank you for submitting your answers to: &lt;br /&gt;
&lt;br /&gt;
$a-&amp;gt;quizname&lt;br /&gt;
&lt;br /&gt;
at:&lt;br /&gt;
&lt;br /&gt;
$a-&amp;gt;submissiontime&lt;br /&gt;
&lt;br /&gt;
This email confirms that we have safely received your answers.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Please do not reply to this email, which was generated automatically by the &lt;br /&gt;
OpenMark online assessment system.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===OU eTMA system===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Subject: Ref: XXXXXX Receipt of assignment ($a-&amp;gt;useridnumber $a-&amp;gt;courseshortname $a-&amp;gt;quizname)&lt;br /&gt;
&lt;br /&gt;
Your assignment, number $a-&amp;gt;quizname for course $a-&amp;gt;courseshortname, was&lt;br /&gt;
received by the eTMA system at $a-&amp;gt;submissiontime.&lt;br /&gt;
                 &lt;br /&gt;
(Your receipt code is: D8CDA7B2).    &amp;lt;--- not relevant to Moodle quiz.&lt;br /&gt;
     &lt;br /&gt;
		    		    		    		  &lt;br /&gt;
&lt;br /&gt;
Your submission included the following files:  &amp;lt;--- not relevant to Moodle quiz.&lt;br /&gt;
Name (Size in Bytes) &lt;br /&gt;
&lt;br /&gt;
TMA05.doc(114,688 bytes)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**********************************************************************************&lt;br /&gt;
The University has to ensure as far as possible that the work submitted by&lt;br /&gt;
students is their own and does not contain any unreferenced material from other&lt;br /&gt;
sources.  The University statement &amp;quot;What constitutes plagiarism or cheating&amp;quot;&lt;br /&gt;
appears in your Assessment Handbook and you are expected to have familiarised&lt;br /&gt;
yourself with it. Please be aware that the University may subject your work to a&lt;br /&gt;
computerised check for plagiarism. &lt;br /&gt;
&lt;br /&gt;
This is an automated reply from the Open University eTMA system.  Please do not&lt;br /&gt;
reply to this email address as the mailbox is not monitored.  If you have any&lt;br /&gt;
queries please email XXX@XXXX.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=74185 Please discuss this proposal in this forum thread]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Element_Library&amp;diff=64575</id>
		<title>Element Library</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Element_Library&amp;diff=64575"/>
		<updated>2025-02-10T08:22:51Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Element Library&lt;br /&gt;
|state = Specification&lt;br /&gt;
|tracker = https://tracker.moodle.org/browse/MDL-45770&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=261202&lt;br /&gt;
|assignee = Damyon, Sam&lt;br /&gt;
}}&lt;br /&gt;
{{Abandoned|forumurl=https://moodle.org/mod/forum/discuss.php?d=261202}}&lt;br /&gt;
The element library will be a new admin tool that will display the output from a list of renderer methods / renderables. The target users for the tool are:&lt;br /&gt;
* Themers, used to test all the existing renderables in a newly developed theme&lt;br /&gt;
* Developers, used to see an organized list of all the renderables that can be used when building new pages (and the docs for them)&lt;br /&gt;
&lt;br /&gt;
The requirements for this tool are:&lt;br /&gt;
* Show a list of renderables / renderer methods for a specific component&lt;br /&gt;
* Show the same renderable / renderer method rendered with different test data&lt;br /&gt;
* Show designer docs on the recommended usage of a specific element&lt;br /&gt;
* Allow easy testing in LTR/RTL and different screen sizes&lt;br /&gt;
* Direct links to the documentation for renderers / renderables&lt;br /&gt;
* Report on the list of renderables used by a renderable / renderer method&lt;br /&gt;
* Testing with different language directions&lt;br /&gt;
&lt;br /&gt;
Some optional requirements:&lt;br /&gt;
* Perform some checks on the renderer to verify it contains no db queries etc&lt;br /&gt;
* Responsive testing in the tool (short-cuts to adjust the window size)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This tool will work by querying a core api for getting a list of renderer_sample_base instances from each plugin. The renderer_sample_base is an abstract class that provides documentation and an example rendering of either a renderer method or a renderable. &lt;br /&gt;
&lt;br /&gt;
== How to add something to the element library (for developers) ==&lt;br /&gt;
&lt;br /&gt;
Each &amp;quot;thing&amp;quot; in the element library - is rendered by an instance of a \core\output\renderer_sample_base class. &lt;br /&gt;
&lt;br /&gt;
For a plugin (or core) to add a new &amp;quot;thing&amp;quot; they must:&lt;br /&gt;
&lt;br /&gt;
A) Implement the tests in subclasses of &amp;quot;\core\output\renderer_sample_base&amp;quot;. These classes can have any name, but it is recommended to name them as &amp;quot;\{plugin namespace}\output\XXX_renderer_sample&amp;quot;. Each test must define a &amp;quot;execute()&amp;quot; method which produces the output, as well as supply developer docs, a name for the test and a category.  &lt;br /&gt;
&lt;br /&gt;
Note: the renderer should be able to produce it&#039;s output relying completely on the data contained in its own arguments or the renderable. If it is performing additional DB queries etc - it will probably fail when provided with &amp;quot;mock&amp;quot; data. In this situation, you should consider refactoring the renderer so it does not perform DB queries. &lt;br /&gt;
&lt;br /&gt;
B) Extend the abstract class &amp;quot;\core\output\renderer_sample_generator_base&amp;quot; with a new class named &amp;quot;\{plugin namespace}\output\renderer_sample_generator&amp;quot;. This class needs to extend &amp;quot;\core\output\renderer_sample_generator_base&amp;quot;. There is one function to implement, which is the &amp;quot;create_samples&amp;quot; function which accepts no arguments and returns a list of subclasses of &amp;quot;\core\output\renderer_sample_base&amp;quot; (implemented in step A). &lt;br /&gt;
&lt;br /&gt;
Note - the non-namespaced class name &amp;quot;{plugin name}_output_renderer_sample_generator&amp;quot; is also supported.&lt;br /&gt;
&lt;br /&gt;
=== Example: Adding &amp;quot;Assign user summary&amp;quot; (TODO - change this example to a core renderable) ===&lt;br /&gt;
&lt;br /&gt;
A) Add a new class &amp;quot;\mod_assign\output\assign_user_summary_renderer_sample&amp;quot; which extends &amp;quot;\core\output\renderer_sample_base&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This class should set the &amp;quot;name, docs and category&amp;quot; class variables in it&#039;s constructor. The &amp;quot;execute&amp;quot; method should create a &amp;quot;assign_user_summary&amp;quot; instance filled with dummy data, get a &#039;mod_assign&#039; renderer and call render on the &amp;quot;assign_user_dummy&amp;quot; class.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
File: mod/assign/classes/output/assign_user_summary_renderer_sample.php&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace mod_assign\output;&lt;br /&gt;
&lt;br /&gt;
class assign_user_summary_renderer_sample extends \core\output\renderer_sample_base {&lt;br /&gt;
&lt;br /&gt;
    public function __construct() {&lt;br /&gt;
        $this-&amp;gt;name = &#039;Assign user summary&#039;;&lt;br /&gt;
        $this-&amp;gt;docs = &#039;A user summary object that is used to display information about a user in multiple places in mod_assign.&#039;;&lt;br /&gt;
        $this-&amp;gt;category = \core\output\renderer_sample_base::CATEGORY_COMPONENT;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function execute() {&lt;br /&gt;
        global $CFG, $PAGE;&lt;br /&gt;
&lt;br /&gt;
        require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/renderable.php&#039;);&lt;br /&gt;
&lt;br /&gt;
        $renderer = $PAGE-&amp;gt;get_renderer(&#039;mod_assign&#039;);&lt;br /&gt;
        $mockuser = guest_user();&lt;br /&gt;
        $mockcourseid = 5;&lt;br /&gt;
        $viewfullnames = true;&lt;br /&gt;
        $blindmarking = false;&lt;br /&gt;
        $mockuniqueidforuser = 5;&lt;br /&gt;
        $mockextrauserfields = array();&lt;br /&gt;
        $suspendeduser = false;&lt;br /&gt;
&lt;br /&gt;
        $renderable = new \assign_user_summary($mockuser,&lt;br /&gt;
                                              $mockcourseid,&lt;br /&gt;
                                              $viewfullnames,&lt;br /&gt;
                                              $blindmarking,&lt;br /&gt;
                                              $mockuniqueidforuser,&lt;br /&gt;
                                              $mockextrauserfields,&lt;br /&gt;
                                              $suspendeduser);&lt;br /&gt;
&lt;br /&gt;
        return $renderer-&amp;gt;render($renderable);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B) Implement the renderable_sample_generator for mod_assign&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
File: mod/assign/classes/output/renderable_sample_generator.php&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
namespace mod_assign\output;&lt;br /&gt;
&lt;br /&gt;
class renderer_sample_generator extends \core\output\renderer_sample_generator_base {&lt;br /&gt;
    public function create_samples() {&lt;br /&gt;
        $tests = array(new assign_user_summary_renderer_sample());&lt;br /&gt;
        return $tests;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Related links ==&lt;br /&gt;
* [[Render library specification]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Element_HTML_and_CSS_guidelines&amp;diff=64574</id>
		<title>Element HTML and CSS guidelines</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Element_HTML_and_CSS_guidelines&amp;diff=64574"/>
		<updated>2025-02-10T08:22:37Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Renderer consistency&lt;br /&gt;
|state = Specification&lt;br /&gt;
|tracker = https://tracker.moodle.org/browse/MDL-45830&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=261202&lt;br /&gt;
|assignee = Damyon, Sam&lt;br /&gt;
}}&lt;br /&gt;
{{Work in progress|forumurl=https://moodle.org/mod/forum/discuss.php?d=261202}}&lt;br /&gt;
&lt;br /&gt;
This is a guide to writing HTML and CSS for elements within Moodle.&lt;br /&gt;
In the future this will likely become the HTML and CSS guide for output in Moodle as we want to move elements. However at present we don&#039;t want to enforce this for all output, just new conversions to elements.&lt;br /&gt;
&lt;br /&gt;
==Why have a strict guide==&lt;br /&gt;
&lt;br /&gt;
At the time of writing this CSS within Moodle (2.7) themes is in a poor state and has been for a long time. Without previously having a guide we were finding that:&lt;br /&gt;
&lt;br /&gt;
* As there was no formal guide to creating id&#039;s or classes, each developer does their own thing.&lt;br /&gt;
* As there was no formal guide on how to write CSS there were numerous techniques used when writing CSS and no consistency.&lt;br /&gt;
* Majority of pages create unique output and require unique CSS, there is very little re-use of design.&lt;br /&gt;
&lt;br /&gt;
While those points may not sound bad to you consider that in following stats from Moodle 2.7 themes:&lt;br /&gt;
&lt;br /&gt;
* Base theme contains 3802 rulesets with a total of 5800 styles.&lt;br /&gt;
* Bootstrapbase theme contains 5170 rulesets with a total of 9362 styles.&lt;br /&gt;
* Clean theme contains 5172 rulesets with a total of 9366 styles.&lt;br /&gt;
* More theme contains 5177 rulesets with a total of 9063 styles.&lt;br /&gt;
&lt;br /&gt;
You get the picture, several thousand selectors containing nearly 10000 styles.&lt;br /&gt;
&lt;br /&gt;
For Moodle 2.8 we committed to introducing a element library to aid the reuse of design and documenting all aspects of output including a guide on writing CSS for Moodle. This is that guide.&lt;br /&gt;
&lt;br /&gt;
==Our goals==&lt;br /&gt;
&lt;br /&gt;
Its very important to understand what we are trying to achieve with this style guide and output in general.&lt;br /&gt;
&lt;br /&gt;
; Frontend framework agnostic : We want theme designers to be able to apply present and future frontend frameworks to Moodle with minimal effort.&lt;br /&gt;
; Consistent interfaces : We want Moodle to have consistency throughout its interfaces, minimising the amount of frontend design and development that is required in coding and styling an interface.&lt;br /&gt;
; Cleanly formatted HTML and CSS : to minimise both development time and to make our renderers and CSS and more maintainable.&lt;br /&gt;
&lt;br /&gt;
We plan to faciliate these with the following:&lt;br /&gt;
; Elements : Highly re-usable objects to produce HTML, these will be used consistently and relied upon by developers creating interfaces. By having these elements we create a consistent look, interface creation will be much quicker and theme designers through the re-use of a limited number of elements.&lt;br /&gt;
; Element library : A tool to show samples of each element, this can be used to view and test designs. It aids the developer by showing them the elements they can select from when creating an interface, and it aids designers by giving them a test area that doesn&#039;t require them to dig through every page in Moodle.&lt;br /&gt;
; Documentation : We will now have proper documentation on all aspects of output. Including this CSS style guide, a renderer best practices guide, and a guide to creating elements.&lt;br /&gt;
&lt;br /&gt;
==Where to put CSS in Moodle core==&lt;br /&gt;
&lt;br /&gt;
CSS can reside in a number of locations depending upon what you are styling.&lt;br /&gt;
&lt;br /&gt;
Remember it doesn&#039;t matter how many CSS files we end up with, on a production site with Theme designer mode switched off (default) all CSS files will be combined and minimised into a single file that is served to the client.&lt;br /&gt;
Excepting the case of IE where we must split the CSS into several smaller files to work around browser limitations.&lt;br /&gt;
&lt;br /&gt;
===CSS for elements===&lt;br /&gt;
As we are moving to using elements you will find that CSS for elements is where most of the effort is going to go.&lt;br /&gt;
&lt;br /&gt;
CSS for elements should reside within themes only, you will find that elements must be styled in all core base themes, this means at least Bootstrapbase and base.&lt;br /&gt;
&lt;br /&gt;
CSS for elements should be located within either &#039;&#039;&#039;theme/themename/style/elements/elementname.css&#039;&#039;&#039; or &#039;&#039;&#039;theme/themename/less/elements/elementname.css&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The actual CSS file should be named according to the element. As elements can be namespaced we need to ensure that that is reflected in the name of the file.&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Element&lt;br /&gt;
! CSS location in base&lt;br /&gt;
! CSS location in bootstrapbase&lt;br /&gt;
|-&lt;br /&gt;
| \core\output\button&lt;br /&gt;
| style/elements/core_output_button.css&lt;br /&gt;
| less/moodle/elements/core_output_button.css&lt;br /&gt;
|-&lt;br /&gt;
| \core\output\navigation_bar&lt;br /&gt;
| style/elements/core_output_navigation_bar.css&lt;br /&gt;
| less/moodle/elements/core_output_navigation_bar.css&lt;br /&gt;
|-&lt;br /&gt;
| \mod_assign\output\user_submission&lt;br /&gt;
| style/elements/mod_assign_output_user_submission.css&lt;br /&gt;
| less/moodle/elements/mod_assign_output_user_submission.css&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These will still need to be included in the theme, by which ever means is relevant.&lt;br /&gt;
If you are using &#039;&#039;.css&#039;&#039; files like the base theme does then you will use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// In your themes config.php&lt;br /&gt;
$THEME-&amp;gt;sheets = array(&lt;br /&gt;
    &#039;elements/core_output_button&#039;,&lt;br /&gt;
    &#039;elements/core_output_navigation_bar&#039;,&lt;br /&gt;
    &#039;elements/mod_assign_output_user_submission&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are using less as bootstrapbase does then you will use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
/** In your primary less file **/&lt;br /&gt;
@import &amp;quot;moodle/elements/core_output_button&amp;quot;;&lt;br /&gt;
@import &amp;quot;moodle/elements/core_output_navigation_bar&amp;quot;;&lt;br /&gt;
@import &amp;quot;moodle/elements/mod_assign_output_user_submission&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===General CSS===&lt;br /&gt;
&lt;br /&gt;
This is CSS for the theme that doesn&#039;t relate to a specific element. Hopefully as we convert more and more of Moodles interfaces to use elements we should see less general CSS.&lt;br /&gt;
&lt;br /&gt;
In any case nothing has changed in regards to the location of general CSS.&lt;br /&gt;
; CSS : If your theme is using standard CSS then it must be located within the &#039;&#039;style&#039;&#039; directory of your theme and should be in logically separated files.&lt;br /&gt;
; Less : If your theme is using less then it should be located in a &#039;&#039;less/moodle&#039;&#039; directory within your theme.&lt;br /&gt;
&lt;br /&gt;
We recommend that you separate styles into files based upon the Moodle component being styled. Again as all CSS files get combined into a single file on production sites it doesn&#039;t matter how many files you end up with.&lt;br /&gt;
&lt;br /&gt;
This would lead to files named like:&lt;br /&gt;
* style/core.css&lt;br /&gt;
* style/course.css&lt;br /&gt;
* style/mod_forum.css&lt;br /&gt;
&lt;br /&gt;
===Where to put CSS in plugins===&lt;br /&gt;
&lt;br /&gt;
It is possible in Moodle to add CSS stylesheets to all plugins (including core plugins).&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle always looks for a &#039;&#039;styles.css&#039;&#039; file within your plugins directory, and it also looks for a styles_themename.css where themename is the name of the currect theme being used.&lt;br /&gt;
&lt;br /&gt;
For instance the following could be added to the forum module:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;mod/forum/styles.css&#039;&#039;: Used all the time.&lt;br /&gt;
* &#039;&#039;mod/forum/styles_base.css&#039;&#039; : Used when the user is using the base theme.&lt;br /&gt;
* &#039;&#039;mod/forum/styles_bootstrapbase.css&#039;&#039; : Used when the user is using the bootstrapbase theme.&lt;br /&gt;
* &#039;&#039;mod/forum/styles_clean.css&#039;&#039; : Used when the user is using the clean theme.&lt;br /&gt;
&lt;br /&gt;
===CSS in core plugins===&lt;br /&gt;
&lt;br /&gt;
For core plugins only styles.css is permitted and it should only ever contain styles essential to the presentation of the plugin.&amp;lt;br /&amp;gt;&lt;br /&gt;
At present styles essential for the display of the plugin are allowed here, however when the plugin interfaces have been converted to use elements this file should be nearly empty and contain only the following:&lt;br /&gt;
* Images, icons and text used for visual presentation such as icons to notify state (expanded/collapsed, warnings...)&lt;br /&gt;
* Accessiblity orientated styles required to make the interface accessible.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Under no circumstances should it contain any visual stylings such as border, rounded corners, and background colours not associated with state.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==HTML==&lt;br /&gt;
&lt;br /&gt;
The following sections detail rules in place for writing HTML.&lt;br /&gt;
&lt;br /&gt;
Before we start a couple of general recommendations:&lt;br /&gt;
&lt;br /&gt;
; Use hyphens rather than underscores when concatenating strings in attributes : for example &#039;&#039;.course-new-activity-chooser&#039;&#039; instead of &#039;&#039;.course_new_activity_chooser&#039;&#039;. By all doing this we will have a more consistent appearance and as We use underscores as part of frankenstyle which is prominent in CSS helps us to reduce the chance of naming conflicts.&lt;br /&gt;
; Think semantics - but don&#039;t get caught up in it : Semantic CSS is beautiful CSS lending itself ultimately to the redesign that is going to happen. But enforcing a semantic design can be an arduous journey. Instead we encourage semantic CSS but are happy to see non-semantic CSS when it is for the greater good.&lt;br /&gt;
&lt;br /&gt;
===Using the ID attribute===&lt;br /&gt;
&lt;br /&gt;
The situation of having a single JavaScript driven element was considered but even then it is better to style only classes and other attributes as we can&#039;t be sure what the future holds.&lt;br /&gt;
&lt;br /&gt;
There are three rules you should follow when creating an ID:&lt;br /&gt;
&lt;br /&gt;
# They should only be given to elements and HTML nodes that need to be interacted with by JavaScript.&lt;br /&gt;
# It should always start with &#039;&#039;&#039;m-&#039;&#039;&#039; &#039;&#039;(see note below)&#039;&#039;&lt;br /&gt;
# The actual ID should be descriptive of the node and contents as a whole unit. It must fully and concisely describe its purpose.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in an ideal world ID&#039;s should not be used for styling.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Good&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;m-dock&amp;quot;&amp;gt; ... &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;m-course-new-activity-chooser&amp;quot;&amp;gt; ... &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bad&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
It doesn&#039;t have the m- prefix&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;dock&amp;quot;&amp;gt; ... &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
This may appear OK at first but when you think about it selecting an activity within Moodle&lt;br /&gt;
is something that is done in multiple places and the this widget may not be applicable to&lt;br /&gt;
every place, as there may be other activity selector JS one day introduced having a&lt;br /&gt;
more complete ID is important&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;m-activity-selector&amp;quot;&amp;gt; ... &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The requirement to use m- prefix is entirely new, this has been created as this instantly reduces the chances of conflicting with present and future frontend frameworks that may be adopted by core or third party themes. Aiding our goal of being frontend framework agnostic.&amp;lt;br /&amp;gt;&lt;br /&gt;
It will also help reduce the chance of conflicts in any third party code that may be used either by us in core, or by outside developers in their own code.&lt;br /&gt;
Moodle ID&#039;s will also be much more easily recognisable which we expect will be a benefit as JavaScript use in Moodle continues to increase.&lt;br /&gt;
&lt;br /&gt;
===Naming CSS classes===&lt;br /&gt;
&lt;br /&gt;
This is where a bit of organisation goes a long way and we want to be reasonably thorough in a consistent naming scheme and implementation.&lt;br /&gt;
&lt;br /&gt;
The very first thing to mention is that all classes in Moodle must now be prefixed by *m-*.&lt;br /&gt;
This instantly identifes a class as belonging to Moodle, it aids us in avoiding conflicts with any non-Moodle css that may be loaded, and it is part of our framework agnostic plan.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
All CSS classes must start with *m-*&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are several prefix that are used within Moodle output now that should not be used as prefixs for classes unless they are serving the desired purpose.&lt;br /&gt;
&lt;br /&gt;
Reserved prefixes are:&lt;br /&gt;
&lt;br /&gt;
; m-element : Prefix used on element classes, where m-element preceeds the name of the element, e.g. m-element-button, m-element-search&lt;br /&gt;
; m-state : Prefix used for CSS classes representing the state of an item, e.g. m-state-disabled, m-state-active, m-state-expanded.&lt;br /&gt;
; m-grid : Prefix used for creating HTML grids.&lt;br /&gt;
&lt;br /&gt;
====Elements====&lt;br /&gt;
&lt;br /&gt;
Semantic design where it gives the best result, smart design where there is a better solution.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re not already familiar with the idea of semantic CSS then Chris Coylers artical [http://css-tricks.com/semantic-class-names/ What makes for a semantic class name] is a great starting point.&lt;br /&gt;
&lt;br /&gt;
We&#039;ve not commit to adopting any one strict approach for writing CSS. We have adopted atomic design for our HTML elements, a design style which fits nicely with the likes of OOCSS, however be very clear that we are not adopting the OOCSS approach in its entirety. The high level abstraction of the visual aspects of elements into highly reusable agnostic classes does not always lend itself well to the Moodle world in which the we wish to be frontend framework agnostic and support largescale completely customisable themes.&amp;lt;br /&amp;gt;&lt;br /&gt;
The highly reusable classes that appeal to one designer, or to one frontend framework may not apply to another.&amp;lt;br /&amp;gt;&lt;br /&gt;
This decision is also impacted by our current default theme bootstrapbase that does not use well abstracted OOCSS in its design.&lt;br /&gt;
&lt;br /&gt;
Atomic design is going to see us end up with many parent child relationships in our HTML that we must carry through to our CSS. Through atomic design we start with smalled atoms and molecules that get built into larger organisms and placed within layouts.&lt;br /&gt;
&lt;br /&gt;
Every element should have a single class that identifies it as element X.&lt;br /&gt;
&lt;br /&gt;
For instance the button atom will have the class *m-element-button*&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;button class=&amp;quot;m-element-button&amp;quot;&amp;gt;I am a button&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is simply the prefix &amp;quot;m-element&amp;quot; plus the element name.&lt;br /&gt;
&lt;br /&gt;
The purpose of this class is to allow the element to be styled with ease. The class name should be applied to the root node for the element, it should never be applied any lower.&lt;br /&gt;
&lt;br /&gt;
By having one class for the element, and always and only applied to the root node it makes it very easy in HTML to see where one element belongs to another.&lt;br /&gt;
&lt;br /&gt;
The following is an example of the search molecule, which in turn contains two button atoms.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;form class=&amp;quot;m-element-confirmation&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;Are you sure?&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt;Are you sure you want to perform this action?&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;submit&amp;quot; name=&amp;quot;cancel&amp;quot; class=&amp;quot;m-element-button&amp;quot; value=&amp;quot;Cancel&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;submit&amp;quot; name=&amp;quot;continue&amp;quot; class=&amp;quot;m-element-button&amp;quot; value=&amp;quot;Continue&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We&#039;ve chosen to partially adopt BEM as a CSS standard when writing CSS for elements.&lt;br /&gt;
&lt;br /&gt;
BEM stands for Block-Element-Modifer. It is a notation format for use with CSS to better describe the relationship between a component and it&#039;s constituent parts.&lt;br /&gt;
&lt;br /&gt;
The notation is simple and consists of just 3 variants:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.block {}&lt;br /&gt;
.block__element {}&lt;br /&gt;
.block--modifier {} &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;.block&#039;&#039; class represents our component e.g. .site-nav&lt;br /&gt;
* &#039;&#039;.block__element&#039;&#039; class represents part of our overall component e.g. .site-nav__link (&#039;&#039;&#039;NB:&#039;&#039;&#039; we use 2 underscores between the block prefix and the element suffix to distinguish it from being part of a hyphenated class name)&lt;br /&gt;
* &#039;&#039;.block--modifier&#039;&#039; class represents a variation in the type or state of our component e.g. .site-nav--vertical would allow us to vary the display of our navigation links. (&#039;&#039;&#039;NB:&#039;&#039;&#039; we use 2 dashes between the block prefix and the modifier suffix)&lt;br /&gt;
&lt;br /&gt;
Let&#039;s apply the BEM notation to something more tangible and define a simple abstraction for a bottle component:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.bottle {}&lt;br /&gt;
.bottle__cap {} &lt;br /&gt;
.bottle__label {} &lt;br /&gt;
.bottle__branding {} // a logo  &lt;br /&gt;
.bottle--screwcap {} // a variation on a standard bottle&lt;br /&gt;
.bottle--corked {}&lt;br /&gt;
.bottle--empty {} // our bottle is in an empty state&lt;br /&gt;
.bottle--recycled {} // our bottle is in a recycled state&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and this might be how we would markup our bottle component:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!-- lets pick a general purpose container --&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;bottle&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;header class=&amp;quot;bottle__cap&amp;quot;&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
  &amp;lt;p class=&amp;quot;bottle__label&amp;quot;&amp;gt;Natural Spring Water&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;img class=&amp;quot;bottle__branding&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- what if we wanted wine instead? --&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;bottle bottle--corked&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;header class=&amp;quot;bottle__cap&amp;quot;&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
  &amp;lt;p class=&amp;quot;bottle__label&amp;quot;&amp;gt;Cheap plonk!&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;img class=&amp;quot;bottle__branding&amp;quot; /&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- what if we&#039;re all out? --&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;bottle bottle--corked bottle--empty&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;header class=&amp;quot;bottle__cap&amp;quot;&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
  &amp;lt;p class=&amp;quot;bottle__label&amp;quot;&amp;gt;The good stuff!&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;img class=&amp;quot;bottle__branding&amp;quot; /&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So you can see, using BEM notation, we can be very expressive in the definition of the elements that make up our pages. And as an added bonus, we are &lt;br /&gt;
building up a repository of components that we can reuse elsewhere in our pages.&lt;br /&gt;
&lt;br /&gt;
Lets say for the purposes of this example that our bottle component includes a list of ingredients. We don&#039;t need anything fancy, just a regular old list with all the default formatting removed:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.list-bare {&lt;br /&gt;
// remove default bullets, margin and padding!&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This kind of list sounds like something we could use elsewhere, so instead of defining it as part of our bottle component, lets make it a standalone component:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;bottle bottle--corked&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;header class=&amp;quot;bottle__cap&amp;quot;&amp;gt;&amp;lt;/header&amp;gt;&lt;br /&gt;
  &amp;lt;p class=&amp;quot;bottle__label&amp;quot;&amp;gt;The good stuff!&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;img class=&amp;quot;bottle__branding&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;h3&amp;gt;Ingrediants&amp;lt;/h3&amp;gt;&lt;br /&gt;
  &amp;lt;ul class=&amp;quot;list-bare&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Lots of Grapes&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;A dash of Yeast&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;A whole lot of love&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, when we need to use a simple unstyled list, we have a component to do just that. The longer you work with BEM notation, the more aware you become of the potential reuse of your components and size of your stylesheets become smaller and more manageable.  &lt;br /&gt;
&lt;br /&gt;
You&#039;ll notice in the example a little further up that there is no way to style the continue button differently from the cancel button without relying on its name attribute, something we certainly don&#039;t want to do.&lt;br /&gt;
The BEM standard comes into play here in naming the classes, the following shows how you would apply BEM to show the purpose of each button in a way that can be easily interpreted and styled in CSS. We will add additional classes to our 2 input elements to set them apart from standard buttons. You can consider &#039;&#039;m-element-button&#039;&#039; as a base class upon which we can build many variants for different purposes. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;form class=&amp;quot;m-element-confirmation&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3 class=&amp;quot;m-element-confirmation__title&amp;quot;&amp;gt;Are you sure?&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;p class=&amp;quot;m-element-confirmation__text&amp;quot;&amp;gt;Are you sure you want to perform this action?&amp;lt;/p&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;submit&amp;quot; name=&amp;quot;cancel&amp;quot; class=&amp;quot;m-element-button &#039;&#039;&#039;m-element-button--cancel&#039;&#039;&#039;&amp;quot; value=&amp;quot;Cancel&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;submit&amp;quot; name=&amp;quot;continue&amp;quot; class=&amp;quot;m-element-button &#039;&#039;&#039;m-element-button--continue&#039;&#039;&#039;&amp;quot; value=&amp;quot;Continue&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By including the class name for &#039;&#039;m-element-button--continue&#039;&#039; one of our form buttons assumes the additional styles we defined for our form&#039;s primary action. &lt;br /&gt;
&lt;br /&gt;
Now to explain the idea of intent.&lt;br /&gt;
An intent is when a single element takes on a different apprearance to convey a specific meaning. A little bit like a state, but with more meaning.&lt;br /&gt;
An easy example is notifications where you will no doubt be familiar with the idea of having a error notifications, warning notifications, success notification etc. Each of error, warning, and success is a intent.&lt;br /&gt;
&lt;br /&gt;
The following shows how this would work:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!-- A standard notification --&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;m-element-notification&amp;quot;&amp;gt;You have not changed your password in the past 60 days&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- A warning --&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;m-element-notification m-element-notification--warning&amp;quot;&amp;gt;You have not changed your password in the past 60 days&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Grids====&lt;br /&gt;
&lt;br /&gt;
We need to adopt a single grid framework.&lt;br /&gt;
&lt;br /&gt;
Personally I don&#039;t think we should use pure bootstrap or pure YUI, instead we should choose one of these and build it use our class name structures.&lt;br /&gt;
&lt;br /&gt;
All grid classes should start with m-grid.&lt;br /&gt;
&lt;br /&gt;
==CSS==&lt;br /&gt;
&lt;br /&gt;
Before we begin lets lay down some ground level goals, things that will help us achieve clear and understandable CSS in the future.&lt;br /&gt;
* Formatting, ordering, alignment, and spacing are all important in having CSS that can be easily read by others.&lt;br /&gt;
* Don&#039;t optimise your CSS, be verbose and stick to the styles in this guide. We have tools that will handle optimisation for you.&lt;br /&gt;
* Never use *!important* in your CSS unless it is absolutely impossible to avoid doing so.&lt;br /&gt;
&lt;br /&gt;
===Terminology===&lt;br /&gt;
&lt;br /&gt;
Its important that when we are speaking about CSS we are speaking the same language.&lt;br /&gt;
Lets look at the following example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.m-page .m-selector-1,&lt;br /&gt;
.m-page .m-selector-2,&lt;br /&gt;
.m-page .m-selector-3 {&lt;br /&gt;
    background-color: #FFF;&lt;br /&gt;
    color: #000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.m-selector-1 {&lt;br /&gt;
    margin: 1em;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; Ruleset : Each of the two rules is a single *ruleset*.&lt;br /&gt;
; Rule: _.m-page .m-selector-1_ is a rule.&lt;br /&gt;
; Selector : _.m-selector-1_ is a *selector*, it is a single part of a rule.&lt;br /&gt;
; Declaration : _background-color: #FFF_ is a declaration.&lt;br /&gt;
;&lt;br /&gt;
&lt;br /&gt;
===Essential formatting===&lt;br /&gt;
&lt;br /&gt;
The following are the guies for writing CSS.&lt;br /&gt;
&lt;br /&gt;
* Always use spaces - never use tabs. All editors can be configured to do it.&lt;br /&gt;
* Indent by 4 spaces - never more, never less.&lt;br /&gt;
* A single empty line between rulesets to maintain consistent spacing of rules.&lt;br /&gt;
* One rule per line.&lt;br /&gt;
* A single space between each selector in a rule.&lt;br /&gt;
* No space between a rule and the comma in a ruleset.&lt;br /&gt;
* A single space between a selector and the opening brace of a ruleset.&lt;br /&gt;
* One level of indentation before each declaration.&lt;br /&gt;
* A single space the colon in a declaration.&lt;br /&gt;
* A single space after each item in a declaration containing multiple items.&lt;br /&gt;
&lt;br /&gt;
The following shows how the above rules apply:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
.m-selector-1,&lt;br /&gt;
.m-selector-2 .m-selector-3 {&lt;br /&gt;
    background: #ffa800 url(&amp;quot;background.png&amp;quot;) no-repeat right top;&lt;br /&gt;
    border: 1px solid #000;&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    font-family: arial, sans-serif;&lt;br /&gt;
    margin: 5px 10px;&lt;br /&gt;
    padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.m-selector-4 {&lt;br /&gt;
    border-radius: 3px;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===General rules===&lt;br /&gt;
&lt;br /&gt;
Declaration ordering is the very first thing to discuss. There is no strict rule on how to order your declarations, however there is a recommendation.&lt;br /&gt;
We recommend that you order declarations within a ruleset alphabetically.&lt;br /&gt;
If we all start doing this then when you read CSS written by someone else you will soon learn to very quickly find your way around the declarations within a rule.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
/** Recommended **/&lt;br /&gt;
.m-selector {&lt;br /&gt;
    background-color: #fff;&lt;br /&gt;
    border: 1px solid #000;&lt;br /&gt;
    color: #000;&lt;br /&gt;
    display: block;&lt;br /&gt;
    margin: 5px;&lt;br /&gt;
    padding: 5px;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do not use a measurement unit when writing a 0 value.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
/** Good **/&lt;br /&gt;
.m-selector {&lt;br /&gt;
    margin: 5px 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Bad **/&lt;br /&gt;
.m-selector {&lt;br /&gt;
    margin: 5px 0px;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use lowercase and shorthand values for colours.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
/** Good **/&lt;br /&gt;
.m-selector {&lt;br /&gt;
    background-color: #fff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Bad **/&lt;br /&gt;
.m-selector {&lt;br /&gt;
    background-color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
.m-selector {&lt;br /&gt;
    background-color: #FFFFFF;&lt;br /&gt;
}&lt;br /&gt;
.m-selector {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Always quote variable values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
/** Good **/&lt;br /&gt;
.m-selector[attr=&amp;quot;variable&amp;quot;] {&lt;br /&gt;
    background-image: url(&amp;quot;image.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** Bad **/&lt;br /&gt;
.m-selector[attr=variable] {&lt;br /&gt;
    background-image: url(image.png);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Commenting===&lt;br /&gt;
&lt;br /&gt;
Always comment your CSS and Less.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;css&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Styles for the button atom.&lt;br /&gt;
 */&lt;br /&gt;
.m-element-button {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Rules and exceptions for less===&lt;br /&gt;
&lt;br /&gt;
Need to write some guff on Less.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Render library specification]] - The original output specification for Moodle 2.8&lt;br /&gt;
* [[Output element planning]] - Thoughts on initial elements that should be created.&lt;br /&gt;
* [[Guide to creating output elements]]&lt;br /&gt;
* [[Renderer best practices]]&lt;br /&gt;
* [[Element HTML and CSS guidelines]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Editors&amp;diff=64573</id>
		<title>Editors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Editors&amp;diff=64573"/>
		<updated>2025-02-10T08:21:55Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to add new editors to Moodle and replace or augment TinyMCE.&lt;br /&gt;
&lt;br /&gt;
==Add a new Editor to Moodle==&lt;br /&gt;
&lt;br /&gt;
The editor is a plugin used by Moodle that we can find in the Moodle source files folowing the path  /lib/editor/&lt;br /&gt;
&lt;br /&gt;
Moodle tipically uses the [http://www.tinymce.com/ TinyMCE editor], but other editors can be installed in Moodle. &lt;br /&gt;
&lt;br /&gt;
We can find [https://moodle.org/plugins/browse.php?list=category&amp;amp;id=23 other editors] that can be installed in Moodle. &lt;br /&gt;
&lt;br /&gt;
==TinyMCE==&lt;br /&gt;
&lt;br /&gt;
TinyMCE is an platform-independent web-based JavaScript/HTML WYSIWYG editor control, used as the main Moodle editor plugin.&lt;br /&gt;
&lt;br /&gt;
===Augmenting TinyMCE===&lt;br /&gt;
&lt;br /&gt;
Specific Moodle TinyMCE plugins can be created in order to augment TinyMCE functionalities.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Creating_a_Moodle_specific_TinyMCE_plugin Here] you will find some tips of how to create your own button, a Moodle specific TinyMCE plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TODO:  Finish this page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Editor_file_management&amp;diff=64572</id>
		<title>Editor file management</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Editor_file_management&amp;diff=64572"/>
		<updated>2025-02-10T08:21:43Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
This document is a specification that describes how how the handling of embedded media and attachments will work with and around the editor in Moodle 2.0. &lt;br /&gt;
&lt;br /&gt;
==Embedding media in a text==&lt;br /&gt;
&lt;br /&gt;
Embedded media includes images, videos and sounds that are embedded within a single given HTML text.   These are added using the HTML editor (which in Moodle 2.0 is a modified version of TinyMCE) and stored in the &amp;quot;file area&amp;quot; associated with the text.  This applies to all HTML texts in Moodle 2.0, ranging from simple forum posts to full pages in the Resource module.   These files can be stored in one flat virtual folder, they do not need to be in sub-directories.&lt;br /&gt;
&lt;br /&gt;
The basic procedure for embedding an image is:&lt;br /&gt;
&lt;br /&gt;
* Click on the image button in the editor&lt;br /&gt;
* Click on the &amp;quot;Choose...&amp;quot; button in the editor dialog&lt;br /&gt;
* Use Filepicker to select the file from a repository (or recent files, or upload) with a name&lt;br /&gt;
* IF A FILE WITH THAT NAME ALREADY EXISTS THEN ALTER THE NAME IN MOODLE (eg file.jpg --&amp;gt; file2.jpg)&lt;br /&gt;
* Add metadata and preferences in the editor dialog&lt;br /&gt;
* Insert the image into the text&lt;br /&gt;
&lt;br /&gt;
(This procedure is almost identical for video and audio files as well)&lt;br /&gt;
&lt;br /&gt;
Note: Like most operating system &amp;quot;Open file&amp;quot; dialogs, the filepicker only shows those media types that you are searching for at that time.  For example, if you are looking for video files then repositories which don&#039;t support video files are not shown, and only video files are shown in the remaining repositories (even if other files may be there).&lt;br /&gt;
&lt;br /&gt;
[[Image:Adding_an_image.png]]&lt;br /&gt;
&lt;br /&gt;
(click on this diagram to see the full-sized version of this example)&lt;br /&gt;
&lt;br /&gt;
==Attaching files==&lt;br /&gt;
&lt;br /&gt;
Attached files are for whenever you have a set of files that you want to store and display.  These include forum attachments, assignment submissions, and resource files (including whole mini web-sites).  Attachments need to support subdirectories and require more file management.&lt;br /&gt;
&lt;br /&gt;
The file manager form element is designed for this.&lt;br /&gt;
&lt;br /&gt;
* Click on &amp;quot;Add&amp;quot; in the file manager form element&lt;br /&gt;
* Select a file from a repository (or upload)&lt;br /&gt;
* File is added &lt;br /&gt;
&lt;br /&gt;
This is what the new &amp;quot;file manager&amp;quot; form element will look like in a Moodle form (example is from the &amp;quot;File&amp;quot; resource module):&lt;br /&gt;
&lt;br /&gt;
[[Image:Filemanager.png]]&lt;br /&gt;
&lt;br /&gt;
A second separate menu under the file manager allows you to pick a &amp;quot;main&amp;quot; file for this case.&lt;br /&gt;
&lt;br /&gt;
==Components to build==&lt;br /&gt;
&lt;br /&gt;
===Recent files repository===&lt;br /&gt;
&lt;br /&gt;
Displays a complete paged history of all the files uploaded by the current user, sorted from newest to oldest.&lt;br /&gt;
&lt;br /&gt;
===File manager===&lt;br /&gt;
&lt;br /&gt;
====AJAX version====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The default interface shows the &amp;quot;root&amp;quot; of the file area (screenshots from MDL-16597):&lt;br /&gt;
&lt;br /&gt;
http://tracker.moodle.org/secure/attachment/18132/File+manager+interface+%28on+root%29.png&lt;br /&gt;
&lt;br /&gt;
And once you click on any folder you can go down in the tree:&lt;br /&gt;
&lt;br /&gt;
http://tracker.moodle.org/secure/attachment/18130/File+manaager+interface+%28on+subdir%29.png&lt;br /&gt;
&lt;br /&gt;
When moving a file or folder, you get a little popup browser to choose the destination.&lt;br /&gt;
&lt;br /&gt;
http://tracker.moodle.org/secure/attachment/18128/moving+file+interface.png&lt;br /&gt;
&lt;br /&gt;
====Non-JS version====&lt;br /&gt;
&lt;br /&gt;
(spec to come)&lt;br /&gt;
&lt;br /&gt;
==Discussion==&lt;br /&gt;
&lt;br /&gt;
Discussion:  [http://moodle.org/mod/forum/discuss.php?d=127238 RFC: Editor file management in Moodle 2.0]&lt;br /&gt;
Discussion document:  [https://docs.moodle.org/en/index.php?title=Development:Editor_file_management&amp;amp;oldid=60871 August 3 version of this page]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Draft&amp;diff=64571</id>
		<title>Draft</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Draft&amp;diff=64571"/>
		<updated>2025-02-10T08:21:02Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
A draft is an early version of a document that is not yet complete.&lt;br /&gt;
&lt;br /&gt;
[[es:Borrador]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Development_data_generator&amp;diff=64570</id>
		<title>Development data generator</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Development_data_generator&amp;diff=64570"/>
		<updated>2025-02-10T08:17:50Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
The development data generator tool replaces the previous tool_generator (admin/tool/generator) in Moodle 2.6. It has also been backported (without removing the old one) to Moodle 2.5 as the current Moodle 2.5 tool_generator is not usable.&lt;br /&gt;
&lt;br /&gt;
It contains multiple features to help generate data for development or testing purposes.&lt;br /&gt;
&lt;br /&gt;
# [[Test course generator]]&lt;br /&gt;
# [[Test site generator]]&lt;br /&gt;
# [[JMeter test plan generator]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_April_2013&amp;diff=64569</id>
		<title>Developer meeting April 2013</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_April_2013&amp;diff=64569"/>
		<updated>2025-02-10T08:17:31Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
Developer meeting April 2013&lt;br /&gt;
&lt;br /&gt;
[[Developer meetings]] &amp;gt; April 2013 meeting notes&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Time&lt;br /&gt;
| [http://timeanddate.com/worldclock/fixedtime.html?year=2013&amp;amp;month=4&amp;amp;day=23&amp;amp;hour=13&amp;amp;min=0&amp;amp;sec=0 13:00 UTC on Tuesday, 23 April 2013]&lt;br /&gt;
|-&lt;br /&gt;
| Meeting room&lt;br /&gt;
| [http://www.youtube.com/moodlehq Moodle YouTube channel]&lt;br /&gt;
|-&lt;br /&gt;
| Chat&lt;br /&gt;
| [https://moodle.org/local/chatlogs/info.php Regular Dev chat]&lt;br /&gt;
|-&lt;br /&gt;
| Twitter&lt;br /&gt;
| [https://twitter.com/search?q=%23moodledev #moodledev]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this meeting we focused on the impending Major release.&lt;br /&gt;
&lt;br /&gt;
== Meeting video ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;mediaplayer&amp;gt;http://www.youtube.com/watch?v=qTQyyE7dod4&amp;lt;/mediaplayer&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Meeting notes ==&lt;br /&gt;
&lt;br /&gt;
===[https://docs.moodle.org/dev/images_dev/d/d3/hq-teams.pdf News from Moodle HQ] (Martin Dougiamas)===&lt;br /&gt;
* New HQ teams are being formed: Front-end, back-end, sites&lt;br /&gt;
* New focus and priorities in teams&lt;br /&gt;
&lt;br /&gt;
===[[Moodle_2.5_release_notes|Moodle 2.5]]===&lt;br /&gt;
====[https://docs.moodle.org/25/en/New_features New features page]====&lt;br /&gt;
* Complements release notes&lt;br /&gt;
* Updated for every release&lt;br /&gt;
* Screenshots and quick overview&lt;br /&gt;
* The page to link to when sharing upcoming features&lt;br /&gt;
&lt;br /&gt;
====[[OpenBadges_User_Documentation|Open Badges]] (Simon Coggins and Yuliya Bozhko)====&lt;br /&gt;
* Initiative from Mozilla for achievements across the Web&lt;br /&gt;
* Awards a badge that is an image but also a verifiable certificate&lt;br /&gt;
* Moodle can award badges and show badges from other sites&lt;br /&gt;
* Test site at &amp;lt;s&amp;gt;[http://openbadgestotara.elearning.catalyst.net.nz openbadgestotara.elearning.catalyst.net.nz]&amp;lt;/s&amp;gt; Now decommissioned, use demo.moodle.net instead.&lt;br /&gt;
* Badges can be awarded at site-wide or course levels&lt;br /&gt;
* Create a badge in a course from the Admin menu and provide an image&lt;br /&gt;
* Awarded based on completion of course or activity&lt;br /&gt;
* Awards can be shared and connected to the Mozilla Backpack&lt;br /&gt;
* Mahara may become a Backpack provider in future&lt;br /&gt;
&lt;br /&gt;
====[http://tracker.moodle.org/browse/MDL-38016 Bootstrap themes] (Martin Dougiamas)====&lt;br /&gt;
* Framework for responsive sites&lt;br /&gt;
* Now a new base theme for a new family of themes&lt;br /&gt;
* Will replace current base themes in future&lt;br /&gt;
* Not be the default theme in Moodle yet&lt;br /&gt;
&lt;br /&gt;
====[http://tracker.moodle.org/browse/MDL-38509 Installation of new plugins from moodle.org] (David Mudrak)====&lt;br /&gt;
* Admin tool in Moodle&lt;br /&gt;
* Plugins found in the Directory can be downloaded, validated and installed&lt;br /&gt;
* Downloaded zip files can be installed and uninstalled from within Moodle without file access&lt;br /&gt;
&lt;br /&gt;
====[http://tracker.moodle.org/browse/MDL-30637 Short forms] (Ruslan Kabalin and Frédéric Massart)====&lt;br /&gt;
* Forms are broken into sections that can collapse&lt;br /&gt;
* Fieldsets with required fields, non-validating fields and forced open&lt;br /&gt;
* Developers should review all their forms to see that they still make sense&lt;br /&gt;
* Editor can be simplified to hide editor toolbars&lt;br /&gt;
&lt;br /&gt;
====[http://tracker.moodle.org/browse/MDL-37009 Consistent course listing display] (Marina Glancy)====&lt;br /&gt;
* Course listings are now rendered consistently&lt;br /&gt;
* Themes will be affected by this, but theming should be more consistent in the future&lt;br /&gt;
&lt;br /&gt;
====[http://tracker.moodle.org/browse/MDL-15727 jQuery and jQuery UI supported in add-ons] (Petr Škoda)====&lt;br /&gt;
* JQuery library now available for plugins&lt;br /&gt;
* Not use by core&lt;br /&gt;
&lt;br /&gt;
====[https://tracker.moodle.org/browse/MDL-37127 Shifting our YUI] (Andrew Nicols)====&lt;br /&gt;
* [[Javascript/Shifter]]&lt;br /&gt;
** Should help to improve documentation and allow unit tests&lt;br /&gt;
** JS can be linted for possible errors&lt;br /&gt;
&lt;br /&gt;
====[http://tracker.moodle.org/browse/MDL-35611 Behat tests] (David Monllaó)====&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* Human readable test instructions&lt;br /&gt;
* Tests can be run automatically in a browser&lt;br /&gt;
* About 100 QA tests have been now automated (more to come) https://tracker.moodle.org/browse/MDLQA-5249&lt;br /&gt;
* Some assistance for test writers is provided by a Developer tool in Moodle 2.5&lt;br /&gt;
* [https://github.com/marinaglancy/moodle-tool_behatui Behat screenshotting tool]&lt;br /&gt;
&lt;br /&gt;
====[https://tracker.moodle.org/issues/?jql=fixVersion%20in%20(%222.5%22)%20and%20component%20in%20(Assignment)%20and%20type%20%3D%20Improvement Assignment changes in 2.5] (Damyon Wiese)====&lt;br /&gt;
* Assignment code now validates with code checker&lt;br /&gt;
* More unit tests have been added&lt;br /&gt;
* Docs have been updated&lt;br /&gt;
* New feature: submission history&lt;br /&gt;
** Reattempts (manual or automatic)&lt;br /&gt;
&lt;br /&gt;
===[[Moodle_Mobile_Release_Notes | Mobile app]] (Juan Leyva)===&lt;br /&gt;
* New version released with a more versions planned every two months&lt;br /&gt;
* App can be styled&lt;br /&gt;
* Push notifications to come&lt;br /&gt;
&lt;br /&gt;
===[[GSOC|GSoC]] (Michael de Raadt)===&lt;br /&gt;
* Moodle has been accepted as a participating organisation&lt;br /&gt;
* Students are starting to submit applications to participate with Moodle&lt;br /&gt;
* Students may be found in forums now and in the future&lt;br /&gt;
&lt;br /&gt;
==Attendees==&lt;br /&gt;
Adrian Greeve, Amy Groshek, Andrew Nicols, Ankit Agarwal, Anthony Borrow, Aparup Banerjee, Barbara Ramiro, Bas Brands, Damyon Wiese, Dan Poltawski, Daniele Cordella, Darryl Pogue, David Monllaó, David Mudrak, Davo Smith, Eloy Lafuente, Frédéric Massart, Gareth J Barnard, Helen Foster, Howard Miller, Jason Fowler, Jason Hardin, Jenny Gray, Jérôme Mouneyrac, Juan Leyva, Justin Filip, Marina Glancy, Mark Nelson, Martin Dougiamas, Mary Cooch, Mary Evans, Michael Blake, Michael de Raadt, Mike Churchward, Peter Bulmer, Petr Skoda, Rajesh Taneja, Rex Lorenzo, Sam Hemelryk, Sam Marshall, Tim Hunt, Watermark Neilsen, Yuliya Bozhko... (plus many more via YouTube and Twitter)&lt;br /&gt;
&lt;br /&gt;
==Meeting chat log==&lt;br /&gt;
&amp;lt;div style=&amp;quot;height:300px;overflow:auto;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| ok we are going live&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| can you see us ok?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:47 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Yup&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:47 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| roger that&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Juan Leyva&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:01:59 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:02:04 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Hello all&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:02:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| I&#039;m lost&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:02:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| shouldn&#039;t get an invatation to the hangout?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:02:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Fowler&lt;br /&gt;
| its working here&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:02:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Juan Leyva&lt;br /&gt;
| juanleyvadelgado@gmail.com&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:02:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| the youtube stream is really good here&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:03:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| yeah no lag and clear&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:03:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| anyone get youtube on ipad?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:04:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Fowler&lt;br /&gt;
| and it.crashed...&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:04:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Helen Foster&lt;br /&gt;
| is michaeld writing notes?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:04:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Fowler&lt;br /&gt;
| trying on android&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:04:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| hello&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| Hello all&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| Hello&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| Hiya&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| Hello&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| lo&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| hi there&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Juan Leyva&lt;br /&gt;
| hello&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| bye&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jenny Gray&lt;br /&gt;
| hello&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| We have some other folks from Moodlerooms watching as well&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:46 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| hello!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| hi&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:05:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Fowler&lt;br /&gt;
| can&#039;t get it working again&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:06:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Moodle HQ is a jelly-fish. Suddeny it all makes sense.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:07:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:08:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| heh&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:08:47 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| &lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:08:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| :D&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:08:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Nice bit of recursion in the bottom right there&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:08:53 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mary Evans&lt;br /&gt;
| is there no Hangout?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:09:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| &lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:09:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| Sorry about that not getting there in the end&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:12:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Martin: A couple of people asking in comments about how to get invites to the hangout. May be worth re-mentioning #moodledev and here again&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:12:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| David, hope you got your google hangout email&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:14:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| no&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:14:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| that&#039;s why I asked for it. I expect MD will add/remove people as needed to keep traffic low&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:04 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| clearly&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| here&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (wow i&#039;m seemingly lagging behind by quite a way)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| waves&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| yeah me too as well&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| Hi Yuliya&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:15:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Moodle Meetings: Few people asking about where chat is&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:16:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| ÐŸÑ€Ð¸Ð²ÐµÑ‚ Ð®Ð»Ñ&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:16:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| yep&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:16:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (hehe I am responding to stuff which seemingly happened ages ago)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:16:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Dan, reload the you-tube page?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| then i&#039;ll miss some!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| David, invited you again&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| what email did you use? Got nothing&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Have you tried to click on the &#039;Live&#039; wording on the video?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| just tried it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| what would you like David?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:17:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| open2study, the Australian MOOC platform, has crazy numbers of badges for really trivial things.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:18:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| LOL&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:19:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| i&#039;m just seeing simon doing the demo now. How far behind am I?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:19:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| How long was that URL?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:19:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| can&#039;t wait for openbadges on moodle.org&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:19:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| Yes, helen you should start plannig some&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:19:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| it just switched to the moodlesite for me 10 secs ago&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| Dan P: a few seconds assuming am not lagging myself&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| this is the url: http://openbadgestotara.elearning.catalyst.net.nz/&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| for us simon just started talking about site/course badges&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| I wonder if MoodleRooms is working on a Common Core -&amp;gt; OpenBadges ecosystem&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:33 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Rex&amp;quot; looks like it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:20:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| https://docs.moodle.org/dev/OpenBadges_User_Documentation - documentation that has links to our test site with accounts you can use to try out badges&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:21:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| @aborrow We are not working on that atm&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:21:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| 66 viewers on Youtube&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:21:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Fowler&lt;br /&gt;
| @@&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:22:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| 41 in here&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:22:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| 10 of those are mine&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:22:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:22:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Is there a login we can use to access the demo site?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:24:37 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Rex: pretty sure it was posted on the forums&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:25:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| it&#039;s in the docs&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:25:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| looking&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:25:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Got it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:25:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Rex: you can also download and install 2.5&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:25:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| But you need to setup an open badge API&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:26:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Just seen the time at the top of Simon&#039;s laptop&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:26:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Oh.. I can just use the default settings I guess&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:26:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| wow yes Wed 1.25 am&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:26:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| yeah, 1am here&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:26:59 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| UK/Europe has the best time&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:27:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| Thanks Kiwis&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:27:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| youtube live streams can be played back again right&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:28:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Rex: You can create badges without syncing them with Mozilla.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:28:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| hope you didn&#039;t have to come home from moodle moot party early&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:28:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| nope, we have another person from out team presenting there&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:29:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| FYI Stacey Walker @ Catalyst Europe is working on a Persona auth integration for moodle&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:30:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| does this integrate with oauth for moodle?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:30:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| I don&#039;t think so&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:31:41 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| its not really the same&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:31:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| would be cool to have users compete for a badge&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:31:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| bmbrands, like employee of the month stype thing?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:32:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| Dan P: what do you mean?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:32:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| @a.nicols: yes why not&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:33:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| And &amp;quot;Top five contributors&amp;quot; type stuff&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:33:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jenny Gray&lt;br /&gt;
| could be useful for reputation management stuff - a bit like our useful moodlers group too&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:34:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| great work!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:34:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:34:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| thanks Yuliya&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:34:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| Do you loose course badges if a course is deleted?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:35:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| isnt the badges like a permanent thing? can they be taken away?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:35:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| no, you don&#039;t, all issued badges belong to users&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:35:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| does it have to be synced/sent to external site?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:36:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| (regularly)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:36:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| no, you don&#039;t have to use anything if you don&#039;t want them in Mozilla backpack&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:36:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| suddenly I feel like having a pizza&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:36:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Funny that&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:37:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| thanks yuliya&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:37:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| How difficult is it to maintain 2 core themes now? Is the goal to eventually move to bootstrap as the single core theme?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:37:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:37:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Yuliya Bozhko&lt;br /&gt;
| Someone asking on Twitter: If a course disappears is the badge revoked? Answer: No, there is no such thing as revocation of badges at the moment. I think Mozilla team is working on it, but currently an issued badge cannot be revoked.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:40:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| Is bootstrap being used for the layouts as well? EG: the columns for blocks, etc&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:40:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| watermark: yes using bootstrap grids&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:40:46 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Yuliya, will the badge still be verified as being valid?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Bootstrap can be used for plugin development too.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| Thanks everyone for your hard work on bootstrap!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Not in the hangout&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| When will the folder name &#039;bootstrap&#039; be changed to &#039;bootstrapbase&#039;?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| @bmbrands what do you mean in regards to plugin dev?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Should we bring up the less/sass issue?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:41:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| will the core renderers be rewritten to match bootstrap?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:42:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| or will they continue to be overridden by bootstrap?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:42:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Thanks Martin&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:42:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| https://tracker.moodle.org/browse/MDL-38160&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:42:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| I&#039;ll be presenting about &amp;quot;beyond bootstrap&amp;quot; on the iMoot&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:42:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Very much like YUI shifter in terms of the new dev workflow&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:43:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| JAson, the way it was summarised to me: where there are sensible changes, like adding a consistent class name to all cancel buttons, they will be done in core. WHere it is a bit bootstrap-specific then it will not be done in core.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:43:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| @Rex has a good point; there is a less vs sass discussion going on there&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:43:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| cue questions about what Shifter is ;)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:43:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| There is a FireBug addon called FireLess that can be used for debugging Less.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:43:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| will the be used for icons?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| who are just out of the picture in the Moodle meeting room?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Jason, that one is insane, I think.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| meaning moving towards the use of css icons?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Bootswatches are worth mentioning too&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| Yes, what is the timeline for bootswatch import?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| can a plugin that uses bootstrap+less be used with a theme that isn&#039;t based on bootstrap?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:44:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| variables and css&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:45:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| very easy to us&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:45:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| ah thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:45:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| Aparup Yes, but it wouldn&#039;t get the bootstrap styling&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:45:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| aparup: depends, if you want to use javascript elements no.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:45:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| afaik less has to be compiled anyway&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:46:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| I think you can used Less to generate any css either pre-compiled or client side with JS on the fly.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:46:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| ie: new plugin with styles.css using less + moodle site with old theme that isn&#039;t based on bootstrap.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:46:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| ah thanks Bas&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:47:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Will the new moodle.org (theme) be based on the new bootstrap theme?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:47:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| Yes, .less files are not loaded live by the theme. It&#039;s more a matter of the development workflow.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:47:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anatai&lt;br /&gt;
| both less and scss need to be compiled to css, but less can also be interpreted client side (slower) for testing&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:47:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| You can do it client side but that&#039;s not a good idea for a live site.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:47:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| not yet&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| No only pizaa&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| no screen&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| yup&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| I can see Martin eating Pizza&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| got it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| But you can tinker client side with FireLess and then use &#039;recess&#039; when happy for production.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Git it now.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| ah yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| yep&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| @Bas Is there still more testing to do on Bootstrap in 2.5?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:48:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| I&#039;m not sure that tinkering is necessary when you can set recess to watch all of your less files for changes and automatically recompile your css.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:49:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Again, similar to Shifter, as Andrew mentioned earlier. =)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:49:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| @Amy but with FireLess you can debug client side to understand where to make the changes.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:49:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| gjbarnard: not too much, but testing with addon plugins would be interesting&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:50:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| just notices G+ watermark on video&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:50:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| @Bas Ta, I can make a start with the course format&#039;s I&#039;m responsible for,&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:50:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| :D&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:51:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| this is awesome&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:51:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| That would be very helpful, I think bootstrap would be very interesting for creating new courseformat too using bootstrap javascript&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:51:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| @Bas Interesting concept - what sort of layout do you have in mind?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:52:30 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| Just discovered the &amp;quot;Large player&amp;quot; button on the youtube stream (hides youtube chat and makes video larger)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:52:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| What sever setup is required for this plugin installation to work over and above what&#039;s already required by Moodle?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:52:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| If malicious functions are used, I hope this woudl not get into teh plugins DB!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:52:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jenny Gray&lt;br /&gt;
| install adins: does it warn or could you set it to fail if the plugin isn&#039;t MATURITY_STABLE?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:52:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| marxjohnson00: shouldn&#039;t be anything unusual&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:52:59 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (same as repsoitory plugins etc)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| If you delete a plugin, does it now delete the files? Before Moodle would tell you that you need to delete the files yourself&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| @timhunt - yes I would like to see some type of warning/notice about installing plugins&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| Would this installer find dependencies?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;@Bas PM&amp;lt;/span&amp;gt;me with idea&#039;s and I&#039;d be glad to help with a new course format.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| It should, plugins can define dependancies&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:37 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| Dan P: Does it store them in moodledata dir then?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| @gareth: sure, lets focus on this stuff by David&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:54 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| @jennygray - we do this with core, it seems consistent to provide a similar warning of beta quality or less for plugins&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:54 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Does this support pulling in packages from a source other than moodle.org ?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| marxjohnson00: ah, no. You need to allow the webserver to write the plugin directories&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:53:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| right&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:54:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| cheers&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:54:04 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| its the same process of a normal download and unzip + upgrade moodle&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:54:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| watermark.nielsen: good question&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:54:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| excellent - glad to see the acknowledgement notice, well done!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:54:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Cool&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anatai&lt;br /&gt;
| I really like the pre-check before install, great touch.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| dependencies show up as little red requirements in upgrade screen&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Uninstall also deletes files, right?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| great explanation David&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Marks question^ does it auto get the the dependencies?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Since almost all plugins are on Github it would be great to see some update method or standards when publishing new plugin versions&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| You can download github as zip&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| Moodle.org can pull in from github already&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:55:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Yes but the developer needs to create a zip, upload to the plugin database etc.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:56:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Okay, thanks.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:56:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| Go to &#039;add new version&#039; and click on &#039;add&#039;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:56:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| oh nope doesn&#039;t auto get dependent plugins afaik.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:56:47 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| bmbrands - no pull in directly from github, by using the &#039;github&#039; repo when adding a new version&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:56:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| bmbrands: https://moodle.org/mod/forum/discuss.php?d=222164&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:56:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Validator functions? Such as?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:57:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Is it easy to write an uninstall script in the plugin to remove custom DB tables?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:57:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| @dan: Cool&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:57:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| is there a roll back function?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Very good. Easier to try out new plugins. I don&#039;t have to do our whole git workflow to put plugins on our test server.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Gareth J Barnard: it is done automatically by xmldb&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| to keep the plugin but downgrade/&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Jason, cannot rollback any updates on Moodle.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| @Dan - Very COOL :D - Thanks.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Downgrading requires the upgrade.php file to reverse what it has done, so no.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| Gareth, or you can use: https://docs.moodle.org/dev/Upgrade_API#uninstall.php if anything is not covered&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:58:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| @Davo Thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:59:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| I did not see the UI screen that gets you to sign in blood that you have made a backup before you start.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:59:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| timhunt: there is a tickbox&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:59:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| bmbrands: i think the solution there is the github repository for uploading to Plugins directory. if its just to try/test perhaps there could be an alternative url that can be entered to fetch a zip from.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:59:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Good&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:59:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| although it might not be there from the plugins directory route atm&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;9:59:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| I can see that going wrong just a bit too often ....&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:00:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| ^ wahey&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:00:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| That would be nice, but terrifying&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:00:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| hehe&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:00:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Yes, could get annoying having updates weekly&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:00:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| I&#039;d need to write a lot of unit tests before I was comfortable doing that&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:00:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Cool stuff David&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:01:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| There can be a contact developer button about problems. Or &amp;quot;Send a crash report&amp;quot;, lol.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:01:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Thanks David&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:01:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| thanks. Apu should get half of the credit for sure, this was a real team project.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:01:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| I have made a &amp;quot;microsoft clippy&amp;quot; block for that, still hoping it will be core one day&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:01:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ruslan Kabalin&lt;br /&gt;
| Sorry guys, just learned 10 mins ago that I am supposed to present something... do not have mic and did not have chance to prepare&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:01:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Martin, just demo it!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| MArtin: ^&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ruslan Kabalin&lt;br /&gt;
| I can comment here though&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| marTIN: ^^&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| use QA site&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (or someting on integration)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| It may also be worth demoing the collapsed editor&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:02:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| hehe&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:03:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| try chat&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:03:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Or quiz&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:03:53 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| for 2.6 will there be a focus on important fields showing not the whole section?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:04:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Hmm.. yeah something important, but not required&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:04:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| right&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Oh, I like the collapsed editor&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Demo adding a new Multiple Choice question&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| the idea is to initially have all the fields that are most commonly used&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| shown&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| The heuristic is: Forms with more than 2 sections: any section after the first is collapsed by default.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| then i expand what I need to add&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| ah - some in there too&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:37 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| jennygray: there is warning for anything lower than MATURITY_STABLE&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Right, Jason.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:47 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Jason Hardin: Fred hsa been reworking a lot of the forms in addition to the other work&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:05:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| It is more than that Dan&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| I love the editor toggle&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Easy to override the default.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| If there were an api like advanced&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| any thought to add that new tinymce option for comments?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| that a dev can tag a fields as &amp;quot;initial&amp;quot; or &amp;quot;important&amp;quot;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Jason Hardin: I don&#039;t see it happening any time soon&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Jason, we already have show advanced.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:06:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Jason, in the assignment plugin, the submission type section is made to be opened by default, but none of those options are required. So it is possible to define what sections to leave open&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| vs collapsed&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| there is only so much we can add onto the existing forms library, this is part of the way forward&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| @tim yeah i know that but we dont&#039; have important or initial as a concept&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| advanced is used to hide settings&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| Oh hurrah! policy bugs&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Dan, any followup on the idea of replacing quickforms?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| this would be used to show inputs&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Jason, re-arrange your form to move the important stuff to the top.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| https://tracker.moodle.org/browse/MDL/component/12733&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:07:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| https://tracker.moodle.org/issues/?jql=project%20%3D%20MDL%20AND%20component%20%3D%20Policy%20AND%20status%20%3D%20Open%20ORDER%20BY%20priority%20DESC&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:08:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Thank Colin Chambers for the collapsed editor&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:08:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| @tim that defeats the purpose of grouping fields by identifiable names&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:08:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| Interesting, but it&#039;s not toggling between HTML raw and wysiwyg, both are wysiwyg...&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:08:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| So to get to HTML I have to show the editor and then select HTML view... I have more steps than before...&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:08:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| if only politicians had bugs.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:08:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| @amy: would be nice to have a raw tab for that&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:09:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ruslan Kabalin&lt;br /&gt;
| my pleasure&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:09:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| hello&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:09:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| can I just type?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:09:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Petr Škoda&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:10:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| Basically in 2.5 all course listings will go through renderer. I made screenshots https://www.dropbox.com/sh/ytgtceoahiw5m6u/2tFpM389pW#/&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:10:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Why aren&#039;t they using the QA site?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:11:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| Rex, who are they?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:11:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| We still might correct some CSS things there&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:12:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| Great to have images there, they could be used to create icon buttons for mobile&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:12:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| By the way, screenshots are made using https://github.com/marinaglancy/moodle-tool_behatui&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:12:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| How does that look with 2000 courses?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:12:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| there are settings that limit the number of courses per page&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:13:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| @tim: isn&#039;t the limit set to 200 ?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:13:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| looks like I&#039;m going to have to catch up with the rest of this later - time for the school run; see you all later&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:13:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| No. The OU has many courses.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:13:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| ciao Davo&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:13:30 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| more about settings: https://docs.moodle.org/dev/Courses_lists_upgrade_to_2.5&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:14:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Where are the developer docs for what might break?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:14:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Ah!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:14:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Thanks.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:14:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| hehe&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:15:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| There is a new JS side to it which hasn&#039;t yet landed&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:15:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| unfortunately it was not possible to keep old css because it was different everywhere&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:15:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| no, that&#039;s it. thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:15:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| there is a bit of lag here I think Martin (you keep giving up on us saying stuff)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:16:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Yup - it lets you drill down, and loads the course information on the page&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:16:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Hi!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:17:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| aergh!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:17:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Hi Petr&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:17:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| i didn&#039;t know he was moving in that close!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:17:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| I think he&#039;s trying to look scary&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:17:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| It&#039;s the light that makes it particularly scary&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:18:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jenny Gray&lt;br /&gt;
| presumably we might move up to jquery 2.x when Moodle decides to drop support for older IE versions though?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:19:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| https://docs.moodle.org/dev/jQuery&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:19:37 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| I thought only IE 9+ was supported?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:19:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| Prototype added for 2.6?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:19:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| why is jQuery worried about IE 6?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:19:59 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anatai&lt;br /&gt;
| currently IE 8+ supported&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Jason Hardin, We support IE8&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| FYI YUI supports back to IE6&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| sigh&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:33 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| Mootools for 2.7 ?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Like Petr says, we&#039;re not intentionally breaking IE support&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:41 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| Dojo for 2.8?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| @Eloy, ha ha&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:53 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| jennygray, Not necessarily, but maybe. Althoughwe&#039;ll drop support for IE8 soon, we&#039;ll still try our best to make things work&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:20:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Hopefully the recent changes to use Shifter will help there too&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jenny Gray&lt;br /&gt;
| OU still supporting IE7 in the &amp;quot;try our best&amp;quot; mode&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| I can if you want&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| YUI resets/normalizr&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| gmail addres andrew?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Let Andrew talk&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| andrewrn@gmail.com&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:21:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| though Petr has covered most of it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:22:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| It will help us to write better API docs for our JS, and unit tests&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:22:39 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| nice coer of it too&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:22:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| *cover&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:22:47 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Andrew, what is that good YUI theatre talk about YUI modules?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:22:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| It is worth it!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:23:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| ermm...&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:23:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| The one from Ubuntu One?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:23:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Foxxtrot&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:23:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Moodle 2.5: &#039;we&#039;re sick of the wussy windows devs&#039; :P&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| great job tweeting by tsala&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| yes we can&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Shifter works fine on Windows&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Amy Groshek&lt;br /&gt;
| @Andrew love the haircut. Very nice.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Wow, cut your hair.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| hairloss!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mike Churchward&lt;br /&gt;
| Holy crap! New man!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Wowâ€¦ Mod Andrew. =)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| If anyone wants to encorage Andrew&#039;s hair loss: http://www.justgiving.com/andrewnicols&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| lol, the most commented on thing so far this meeting&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:24:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| I liked the poneytail! But understand the reasons for haircut&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:25:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:25:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Petr Škoda&lt;br /&gt;
| linting - yay!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:26:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| (&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:26:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| I learned a lot from the lint output.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:26:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| I used to understand him better with the long hair, uhm...&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:26:30 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Well, you just add Y.log statements to you code for development.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:26:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Then, they don&#039;t appear in the finished code for people not in dev debug mode.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:27:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| Eloy: you need mod_rmaccent&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:27:30 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Petr Škoda&lt;br /&gt;
| https://docs.moodle.org/dev/jQuery is the jQuery docs page&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:27:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| What shampoo do you use?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:27:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Andrew&#039;s so dreamy!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:27:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| wow, thats a good colour in your face now!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| LOL&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| I keep thinking I am watching a shampoo commercial on youtube&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| I can see ruslan trying to get in the picture&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| with his arms&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| https://docs.moodle.org/dev/YUI https://docs.moodle.org/dev/Javascript/Shifter&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Get LANCs to change the paint colour!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| And https://docs.moodle.org/dev/YUI/Modules is in progress&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:28:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| its gone dark&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:29:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| https://docs.moodle.org/dev/Acceptance_testing&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:30:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| Are you hearing David ok?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| yep&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| yep&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| best english in the season!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (I am used to his spanish accent )&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:48 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| season, or session?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:31:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| year*&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| &lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:02 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Martin Dougiamas, Where were you suggesting I add the links to the new docs?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Helen Foster&lt;br /&gt;
| David sounds great!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| The April 2013 dev meeting page&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:46 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| will do&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:32:53 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| Thanks!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:33:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| could this be used to create performance tests too? this looks easier than doing jmeter scripts.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:33:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| bmbrands: no&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:33:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| It wouldn&#039;t make sense to time the tests as a performance indicator?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:34:04 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (not out of the box, I don&#039;t think.. doubting myself now)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:34:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| not really (there are some &amp;quot;pauses&amp;quot; here and there), and will evolve along the time/depend of the product used.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:34:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| Yes it can&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:34:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| rexlorenzo@gmail.com: they are doing pauses and all kinds of things&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:34:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| its not a very reliable way to do it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:34:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Just a note to developers: MDK (Fred&#039;s plugin) will set behat up for you.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:35:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| No, sure. But I think with lots and lots of tests the pauses will sort of even out.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:35:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| At least it would detect really stupid mistakes.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:35:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| I found another implementation recently - it is useful to run the same test across all/some themes and make screenshots&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:35:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Whoops, when I say plugin, I mean script. It is not a moodle plugin.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:35:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| Post your code again marina.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:35:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| It&#039;s a cool idea&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:36:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| https://github.com/marinaglancy/moodle-tool_behatui&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:36:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| (Y)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:36:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| @marina: coool&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:36:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Marina Glancy&lt;br /&gt;
| I added there a big test for course listings, I&#039;m going to suggest it for theme developers in my course listings doc&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:36:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| it can be used to cover some &amp;quot;key&amp;quot; vualizations.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:37:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| *visualizations.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:37:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| If you have moodle 2.5, you can see the list of steps definitons in: admin/tool/behat/index.php&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:37:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| (aka the vocabulary)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:38:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| Given Marina submits moodle-tool_behatui to Moodle plugins, Then I can automatically install with Aparup&#039;s install button&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:38:37 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| behat is not using the mink plugin to allow for other test servers other than selenium?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:39:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:39:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| in fact I want to try it against others soon (faster and headless with JS support)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:40:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| Hrm... that can help speed up tests though. Using a headless browser, etc&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:40:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| bmbrands&lt;br /&gt;
| have to leave, thanks all&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:40:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| it does help but has issues&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| not all headless support the same funcitonality as selenium&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| for non-js, non-corss-browser ones it already uses headless afaik)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| selenium seems to be the best supported though&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| nah&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| the others have &amp;quot;issues&amp;quot;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| lol, selenium has too&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Mark: yes. The problem is real useers don&#039;t use javascript-less browsers&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| Thanks Bas!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| @eloy, true, but you can get the server to run&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:41:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| i have not gotten others to run onlinux and mac&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| only one or the other&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Oh, are you guys also running behats tests for accessibility? The idea about javascript browsers made me think about it.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| well, I&#039;ve tried zombie and it rocks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| i tried zombie and it failed&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| for the purposes I&#039;m thinking about.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| *javascript-less&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:41 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| rexlorenzo@gmail.com: an interesting side effect of behat tests is that I think it helps us with accessibility&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:42:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| @poltawski: not all tests require JS though - if I just want to confirm that some text appears after hitting a button, I don&#039;t need anything special&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| yeah when Eloy means javascript less it is that the testing software doesn&#039;t need aJS to run the tests&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| not that there is no js testing&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| because we spot things like multiple links with the same meaning&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| grr&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| different meaning&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| same heading, different meaning&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| @watermark.nielsen its already supported with headless browser, if itsnnot got javascript requirement&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:46 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nielsen&lt;br /&gt;
| ah&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| if you want accessibility testing there is a fireeyes plugin that works pretty well it is free&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:43:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| there is an @javascript tag for javascript depdendent tests&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:44:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| http://www.deque.com/deque-fireeyes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:44:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| it si produced by the consulting company Moodlerooms hired to review Moodle&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:44:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| and free to use as long as you are not providing consulting services around it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:44:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| he&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:44:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| meeting interruptus?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:45:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| thats his screen isn&#039;t it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:45:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| keep commentating!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:45:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| music!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:45:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| brasil!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:45:32 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Ijust saw his terminal&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:45:52 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| seeing terminal snow&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| Yip I can see it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| its threre now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| *now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| finally a command line interface!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| its just that its at top of screen&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| DONT TYPE the ROOT&#039;s PASSWORD NOW!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Martin: Click on his window at the bottom. It&#039;s based on who is talking most&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| get him to press enter&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| gone&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| heh&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| wfm ;)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:46:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| I see him!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:47:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| its there now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:47:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| here we go&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:47:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| look you guys look!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:47:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| it&#039;s boring... although last time i was 80 mins looking for them to complete.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Helen Foster&lt;br /&gt;
| wow, how cool is that!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| david is cheating&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| hes just doing it quickly&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| it&#039;s a recorded video! Fake!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| &lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:48:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| eh, have you seen the setType warning, Dan?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| He has a Raspberry Pi controlled mouse ;)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| suspects trained monkeys&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| yes!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| errors not detected&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Does this take screenshots at any points for making sure a page is rendered correctly?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| can you run just the plugin tests?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| yeah, we should have them caught already, grrr&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Such as: this page looks great in Chrome and FF but renders incorrectly in IE8?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:46 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| Jason Hardin: you can run by tag&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| awesome&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| jfilip: yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:49:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| by tag or by name (part of the description)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:50:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Cool, thanks.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:50:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jason Hardin&lt;br /&gt;
| nice&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:50:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| Justin, that&#039;s exactly what Marinas behatui thing does&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:50:25 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Are you guys running also running selenium in windows to test IE? How many different environments are you running selenium or planning to?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:50:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| 2.6 testing won&#039;t be QA testing anymore but &amp;quot;picture testing&amp;quot; instead, lol.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:51:15 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| I&#039;ll take a look at it, thanks for the info.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:51:41 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| Sauce labs, for now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:52:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Which service?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:52:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| https://saucelabs.com/&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:52:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| settype again&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:52:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| https://saucelabs.com/u/moodle&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:52:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| ^ cool&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:53:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| we need to catch all those notices/warnings/debuggins ASAP&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:53:34 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Very cool stuff.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:53:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| awesome stuff, david!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:53:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| now everyone else needs to start writing tests&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:54:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| i want to&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:54:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| (steam was coming out of davids ears when I was in perth)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:54:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| Nice presentations&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:54:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| slides&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:55:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| wasn&#039;t there a pending backport issue for tests to 2.4 ?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:55:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| (evil)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:55:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| (assign ones)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:55:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| yup&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:55:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| aren&#039;t they waiting on Damyon&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:56:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| yup: MDL-37632&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:56:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle Bot&lt;br /&gt;
| https://tracker.moodle.org/browse/MDL-37632 - Backport unit tests for mod/assign/lib.php and mod/assign/lib.php and mod/assign/upgradelib.php to 24&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:56:31 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-V: 0, W: 3, Type: Improvement, Assignee: Damyon Wiese, Priority: Minor, Status: Reopened&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| yay people using the new drag/drop of help&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;10:59:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:00:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| profile description from mdk&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:00:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Davo Smith&lt;br /&gt;
| popped back just in time&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:04:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Will MDL-37490 make it into M2.5?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:04:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle Bot&lt;br /&gt;
| https://tracker.moodle.org/browse/MDL-37490 - Display assignment due date on course page.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:04:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-V: 4, W: 7, Type: New Feature, Assignee: Gareth J Barnard, Priority: Minor, Status: Waiting for integration review&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:05:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Seeing it on youtube now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:05:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:05:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:05:27 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:05:33 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| sbourget&lt;br /&gt;
| yes&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:05:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| another perfect english speaker, yay!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:06:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| the orange looks &amp;quot;too much&amp;quot; for me, lol.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:09:00 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| No such thing as too much orange.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:09:12 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| will it support custom backgrounds?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:09:37 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| typical mobile developer - having even desktop windows resized to 200 x 300 px&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:09:53 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| heh&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:10:04 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| Yes you can change backgrounds and everything via CSS&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:12:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| there is a new setting in Moodle 2.5 that lets you specify the URL to a CSS file&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:12:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| super&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:12:53 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| And the app will get this and use it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:12:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Same goes for language customisations&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:13:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| &lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:13:23 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| And all this is cached in the app&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:13:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| well done1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:14:03 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| It&#039;s a nice app - well done Juan&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:14:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| nice! (browser appears black sometimes in youtube)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:14:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Is the push notifications something similar to what Moodlerooms is proposing for their alert system in here? https://moodle.org/mod/forum/discuss.php?d=223812&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:14:59 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| How can we sent push notifications? Does it use the messaging api?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:28 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| More open. Less free&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:29 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| Haha oh dear&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| lets not get into that now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| rexlorenzo@gmail.com: the notification using messaging system&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Juan Leyva&lt;br /&gt;
| Rex, yes messaging output plugins&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:46 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| &amp;quot;we are legion&amp;quot;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:15:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| We have a server called AirNotifier that will recieve messages from Moodle&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| maberdour&lt;br /&gt;
| Holy crap, been trying out different jabber settings for an hour. Made it in. Thanks @anatai&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| via Message API&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| jabber is sooo simple, lol.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:33 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Martin Dougiamas&lt;br /&gt;
| and send it to Apple/Google and then to your phone&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anatai&lt;br /&gt;
| @maberdour you&#039;re welcome&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| super&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:51 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| exciting&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:55 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| amazing&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:57 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| sam marshall&lt;br /&gt;
| (yeah, how come irc works much better than jabber?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:16:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Thank you&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| yes the notifications i&#039;ve received were cool Jerome&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Juan Leyva&lt;br /&gt;
| https://docs.moodle.org/24/en/Moodle_Mobile_app&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Juan Leyva&lt;br /&gt;
| https://docs.moodle.org/dev/Moodle_Mobile&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:19 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| welcom, G&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| We&#039;ve lost camear on youtube&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:22 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Got your camera now&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:17:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| any updates on MDL-36350 / https://docs.moodle.org/dev/Survey_2_module - it seems to keep getting pushed back - possible GSOC project?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:18:30 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Moodle Bot&lt;br /&gt;
| https://tracker.moodle.org/browse/MDL-36350 - Implement Survey 2 module&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:18:30 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-V: 12, W: 18, Type: New Feature, Assignee: Daniele Cordella, Priority: Major, Status: Open&lt;br /&gt;
| Moodle HQ&lt;br /&gt;
| AFAIK Daniele stil on it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:19:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| afaik Danielle is back, hard working on it, Anthony.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:19:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anthony Borrow&lt;br /&gt;
| good news!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:19:21 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| lag is tricky&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:19:54 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| hi GSOC students watching!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:19:58 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| marxjohnson00&lt;br /&gt;
| 1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:05 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| and Twitter hasn&#039;t been great for it&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:06 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| Brilliant&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| this is way way better&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| 0.5&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:08 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Will this live stream be saved? +1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| +1 though&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:09 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| 1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Video and audio is good.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| 1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Pretty good&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:13 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Better than bbb&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| 0.2&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:17 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| 1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:18 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Harder to see who is in the meeting and chat&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| Could do with the stream running a bit for 15 minutes before hand to give people a chance to get themselves sorted&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:24 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| It worked with very little effort.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| 1&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Yes. Starting the stream earlier woudlbe good.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| google rocks!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Jenny Gray&lt;br /&gt;
| twitter has been surprisingly quiet.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| &lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:43 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| BBB is being used at iMoot 2013.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:20:56 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Andrew Nicols&lt;br /&gt;
| thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:10 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| too many places to check for feedback&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:11 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Gareth J Barnard&lt;br /&gt;
| Thank you all&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:26 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| devs rocks! C&#039;mon!&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:35 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Tim Hunt&lt;br /&gt;
| Thanks.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:36 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Anatai&lt;br /&gt;
| thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:38 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:40 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ankit Agarwal&lt;br /&gt;
| Cya all&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Justin Filip&lt;br /&gt;
| Thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:42 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| mary&lt;br /&gt;
| thanks&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rex Lorenzo&lt;br /&gt;
| Thanks.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:44 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Sam Hemelryk&lt;br /&gt;
| Cool, thanks guys&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:45 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Mark Nelson&lt;br /&gt;
| Ciao.&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Dan Poltawski&lt;br /&gt;
| ciao&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:49 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| (clap)&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:50 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| +1 mojito&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:21:54 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rossiani Wijaya&lt;br /&gt;
| cya&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:22:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Rajesh Taneja&lt;br /&gt;
| cya&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:22:01 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| David Mudrák&lt;br /&gt;
| did I hear &amp;quot;meeting rums?&amp;quot;&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:22:07 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Aparup Banerjee&lt;br /&gt;
| thanks! good night! moodle out yo&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:22:14 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| did i hear &amp;quot;mojito&amp;quot; ?&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:22:16 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Eloy Lafuente (stronk7)&lt;br /&gt;
| lol&lt;br /&gt;
| &amp;lt;span style=&amp;quot;white-space:nowrap&amp;quot;&amp;gt;11:22:20 PM&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_credits_processor&amp;diff=64568</id>
		<title>Developer credits processor</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_credits_processor&amp;diff=64568"/>
		<updated>2025-02-10T08:16:55Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Developer credits processor&lt;br /&gt;
|state = In production&lt;br /&gt;
|tracker = MDLSITE-1663&lt;br /&gt;
|discussion = N/A&lt;br /&gt;
|assignee = [[User:David Mudrak|David Mudrak]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Project goals ==&lt;br /&gt;
&lt;br /&gt;
We need to replace part of the functionality provided by the legacy cvsadmin plugin at moodle.org. The new local plugin /local/dev is supposed to:&lt;br /&gt;
&lt;br /&gt;
* gather activity traces of git commits in the main moodle.git repository&lt;br /&gt;
* gather activity traces of comments and transitions in JIRA&lt;br /&gt;
* assign activity traces to real moodle.org users&lt;br /&gt;
* produce a list of Moodle developers and simple amount of their contribution (per branch and per release)&lt;br /&gt;
&lt;br /&gt;
== Design principles ==&lt;br /&gt;
&lt;br /&gt;
* It must be cheap to display the data to the visitors of moodle.org site (with just one or two SQL queries)&lt;br /&gt;
* Data collecting and processing should be implemented in CLI scripts. Then we can schedule their execution accurately via robust Unix crontab syntax and we don&#039;t pollute Apache&#039;s access logs.&lt;br /&gt;
&lt;br /&gt;
== Overall architecture ==&lt;br /&gt;
&lt;br /&gt;
The following image displays the basic architecture of the plugin and how it applies to the two sources of activity records - moodle.git repository and the JIRA tracker.&lt;br /&gt;
&lt;br /&gt;
[[Image:local_dev_processes.png|thumb|left|466px|Basic processes of collecting and aggregating activity traces in Moodle development]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a table {dev_activity} that is the only one used when displaying the contribution data. A subclass of table_sql is used so it takes care of sorting and pagination.&lt;br /&gt;
&lt;br /&gt;
Rows in the {dev_activity} table are updated by the script cli/aggregate.php. For every tracked activity source (like moodle.git, JIRA or whatever else in the future) there is a class that is responsible for updating its activity metric (eg. gitcommits, gitmerges etc).&lt;br /&gt;
&lt;br /&gt;
There can be various tables for each tracked activity source to hold the data for the aggregating class. These tables are populated with data as needed.&lt;br /&gt;
&lt;br /&gt;
=== Processing moodle.git commits ===&lt;br /&gt;
&lt;br /&gt;
* The plugin keeps its own mirror of moodle.git in moodledata (cloned with --mirror parameter)&lt;br /&gt;
* The script cli/git-commits.php reads commits from all MOODLE_xx_STABLE branches as well as from the master branch and records them in the {dev_git_commits} table&lt;br /&gt;
* The script cli/git-tags.php assigns each commit to the Moodle release it belongs to&lt;br /&gt;
* The script cli/git-aliases.php tries to assign each commit to the real moodle.org user account (based on the email in the commit and eventually any explicit mapping defined in {dev_git_user_aliases} table).&lt;br /&gt;
* The script cli/aggregates.php uses two classes dev_gitcommits_aggregator and dev_gitmerges_aggregator that are responsible for aggregating commits and merges (respectively) and linking them to Moodle versions (by converting the associated Git tag to a Moodle version).&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Datalib_Notes&amp;diff=64567</id>
		<title>Datalib Notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Datalib_Notes&amp;diff=64567"/>
		<updated>2025-02-10T08:16:06Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
== General Datalib usage Notes ==&lt;br /&gt;
&lt;br /&gt;
Couple of discussion threads about usage of datalib are [http://moodle.org/mod/forum/discuss.php?d=43456 here] and [http://moodle.org/mod/forum/discuss.php?d=38183 here].&lt;br /&gt;
&lt;br /&gt;
== Advanced Usage: get_recordset() ==&lt;br /&gt;
&lt;br /&gt;
There&#039;s a new series of function calls in datalib that were introduced shortly after 1.5: get_recordset() and friends. It takes a bit of work to make good use of them, they are definitely useful.&lt;br /&gt;
&lt;br /&gt;
The function calls themselves take similar parameters to the get_records() family, and return an AdoDB recordset. In most situations, the right thing is to use get_records(), making sure that you are selecting a limited number of records (use LIMIT of course wink ), and that you are clearly fetching only the fields you need. That is enough for 99% of the cases. Stop reading now, use get_records(), and done.&lt;br /&gt;
&lt;br /&gt;
Easy!&lt;br /&gt;
&lt;br /&gt;
Now, there are some cases where we need to perform huge selects. And the downside of the get_records() machinery is that it allocates it all in RAM -- and if indeed records &amp;gt; than RAM, we are in trouble. This mostly affects batch processing in admin/cron.php (backups for instance) and the silly sync scripts we have in some auth and enrolment plugins.&lt;br /&gt;
&lt;br /&gt;
In those cases, where you have no option but to SELECT all the users, or all the courses, get_recordset() really shines. As you get an AdoDB recordset, you can iterate through it very fast, and with very low memory usage. I have prepared and profiled some samples and found that to keep that advantage you have to be very careful how you use it.&lt;br /&gt;
&lt;br /&gt;
I started testing with a large mdl_user table with 46K users, stored in PostgreSQL locally (socket connection). Here is a rundown of the code and rough timings...&lt;br /&gt;
&lt;br /&gt;
The traditional get_records() is fast (~14s), but it consumes 296MB of memory. It looks like:&lt;br /&gt;
&lt;br /&gt;
  $users = get_records(&#039;user&#039;);&lt;br /&gt;
&lt;br /&gt;
So the next thing was to check that just triggering the SELECT was fast, and that fetching and re-shaping all that data into memory was an expensive step. get_recordset() in itself never fetches the data into PHP-space, so it takes only 4.8MB and 1.4s:&lt;br /&gt;
&lt;br /&gt;
  $users = get_recordset(&#039;user&#039;);&lt;br /&gt;
&lt;br /&gt;
Next I tried using get_recordset() with FetchNextObj() which looked quite convenient, because it will yield each record in an object, similar to the objects that get_records() returns inside the array. The memory usage stayed the same (4.8M), but this is very slow (~65s):&lt;br /&gt;
&lt;br /&gt;
  $users = get_recordset(&#039;user&#039;);&lt;br /&gt;
  while($v = $users-&amp;gt;FetchNextObj()){&lt;br /&gt;
      // do something &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Internally, get_records() is using GetAssoc(), so I looked in there to se faster ways of getting at the data. Apparently, the trick is in reading the $rs-&amp;gt;fields array and using MoveNext(). So this loop still takes 4.8MB and walks the 46K user records in 4s:&lt;br /&gt;
&lt;br /&gt;
  $users = get_recordset(&#039;user&#039;);&lt;br /&gt;
  while(!$users-&amp;gt;EOF) {&lt;br /&gt;
      $user = $users-&amp;gt;fields;&lt;br /&gt;
      // do something&lt;br /&gt;
      $users-&amp;gt;MoveNext();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Naturally, as soon as you start doing useful things, this will take longer to exec. The core advantage, however, is that it can give you comparable performance to get_records() but with very low memory usage.&lt;br /&gt;
&lt;br /&gt;
There is an interesting [http://moodle.org/mod/forum/discuss.php?d=45794 discussion about get_recordset() in the General Developer Forum].&lt;br /&gt;
&lt;br /&gt;
== Moodle 2 ==&lt;br /&gt;
Note, that this documentation is not valid for Moodle 2. Please refer to https://docs.moodle.org/dev/Data_manipulation_API#Using_Recordsets&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Database_collation_issue&amp;diff=64566</id>
		<title>Database collation issue</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Database_collation_issue&amp;diff=64566"/>
		<updated>2025-02-10T08:14:57Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Database collation issue&lt;br /&gt;
|state = Specification in progress&lt;br /&gt;
|tracker = MDL-36208&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=214564&lt;br /&gt;
|assignee = &#039;&#039;Hero required&#039;&#039;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
Database store text data using a particular &#039;&#039;&#039;character set&#039;&#039;&#039;. Moodle uses UTF-8, which is a good thing, since UTF-8 can represent almost any character ever.&lt;br /&gt;
&lt;br /&gt;
Text data is also stored with an associated &#039;&#039;&#039;collation&#039;&#039;&#039;. This affects how the values are sorted and compared. For example, different languages have different sort-orders, which depend on which alphabet they use. For example in German the &#039;&#039;&#039;ß&#039;&#039;&#039; character should come just after &#039;&#039;&#039;S&#039;&#039;&#039; (and &#039;&#039;&#039;s&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Collations typically come in two forms, case sensitive, and case-insensitive. If you are using a case-insensitive collation, then not only do &#039;x&#039; and &#039;X&#039; get sorted the same, but actually, the database thinks that &#039;x&#039; = &#039;X&#039;.&lt;br /&gt;
&lt;br /&gt;
Operations like JOINs are typically much faster if both tables (columns) use the same collation.&lt;br /&gt;
&lt;br /&gt;
== The problems ==&lt;br /&gt;
&lt;br /&gt;
=== Collation should depend on current language ===&lt;br /&gt;
&lt;br /&gt;
On multi-lingual sites like [https://moodle.org/ moodle.org], different users will all expect reports to be sorted according to their language&#039;s collation rules. If we just specify the collation in database table definition, then all queries for all users have to use the same collation.&lt;br /&gt;
&lt;br /&gt;
Typical bugs:&lt;br /&gt;
* MDL-30446 Glossary order issues for some collation settings (Postgres)&lt;br /&gt;
&lt;br /&gt;
=== Machine-readable identifiers ===&lt;br /&gt;
&lt;br /&gt;
Moodle stores two sorts for text data:&lt;br /&gt;
* user-visible strings like user.firstname, user.lastname or course.fullname&lt;br /&gt;
* machine-readable identifiers like user.username, course.idnumber or file.filepath&lt;br /&gt;
&lt;br /&gt;
For machine-readable identifiers, the &#039;x&#039; == &#039;X&#039;, or worse &#039;e&#039; == &#039;é&#039; behaviour is really bad, particularly if you want to put a unique index on the column in question. It has lead to bugs like:&lt;br /&gt;
* MDL-29332 Calculated Questions Require Case Sensitive Data Tables (MySQL)&lt;br /&gt;
* MDL-33655 MySQL case insensitivity breaks get_directory_files (MySQL)&lt;br /&gt;
* MDL-34271 improve mysql collation handling&lt;br /&gt;
&lt;br /&gt;
=== Human-readable case-sensitive strings ===&lt;br /&gt;
&lt;br /&gt;
* MDL-22117 Units in numerical questions are acting case sensitive, but not functioning that way&lt;br /&gt;
&lt;br /&gt;
=== MySQL only has localised collations that are case-insensitive ===&lt;br /&gt;
&lt;br /&gt;
If you look at the list of [https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-sets.html MySQL collations], you will see that the only collations that give correctly locale-aware ordering are case-insensitive (the ci bit in utf8_czech_ci), and so suffer from the &#039;x&#039; == &#039;X&#039; and &#039;e&#039; == &#039;é&#039; problem. The only collation that does not have this problem is utf8_bin, which is not the order people want to see.&lt;br /&gt;
&lt;br /&gt;
== Outline solution ==&lt;br /&gt;
&lt;br /&gt;
The proposed solution is simple in outline:&lt;br /&gt;
# Store all data in database tables that use a case-sentistive collation (e.g. utf8_bin).&lt;br /&gt;
# Change all ORDER BY clauses in all SQL that sort text, to specify the correct sort collation, based on the current language.&lt;br /&gt;
&lt;br /&gt;
To support that second part, we will need some helper code, for example, each language pack must specify the right collation to use, for each supported database, for example using new strings in langconfig.php. We will also need an $DB-&amp;gt;sql_order_by_text($column) helper function to return the right SQL fragment like &amp;quot;columnname COLLATE utf8_czech_ci&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Difficulties with the proposed solution ==&lt;br /&gt;
&lt;br /&gt;
=== Transitional period (minor) ===&lt;br /&gt;
&lt;br /&gt;
In the transitional period, when the table definitions have been updated to use a collation like utf8_bin, but before we have found and fixed all SQL queries in Moodle core (and in all third-party plugins) to use sql_order_by_text, then the worst that can happen is that the results of some reports appear in a slightly odd order for some users. The reports will still basically work.&lt;br /&gt;
&lt;br /&gt;
Whenever a problem like this is detected, it will be easy to add the necessary sql_order_by_text call to the code to fix it.&lt;br /&gt;
&lt;br /&gt;
=== Time to do the upgrade (moderate) ===&lt;br /&gt;
&lt;br /&gt;
The amount of time required to upgrade all tables to a new collation is going to be comparable to the time required for the change that changed all unsigned int columns to signed. This was an issue for some large sites.&lt;br /&gt;
&lt;br /&gt;
Like dropping unsigned columns, this is probably a necessary evil that we can live with.&lt;br /&gt;
&lt;br /&gt;
=== Backwards compatibility of identifiers (severe) ===&lt;br /&gt;
&lt;br /&gt;
This is the most serious problem. It affects areas like:&lt;br /&gt;
* What are valid user names? Are user names case-sensitive.&lt;br /&gt;
* For people using integrations like the database authentication and enrolment plugins, or CVS import, it may be that at the moment, the identifiers currently match using case-insensitive collation, but if we changed the database collation to utf8_bin, then things would not longer match. This could cause a real mess.&lt;br /&gt;
&lt;br /&gt;
So, we may have to add an admin option for these areas, where admins can choose if they want case-sensitive or case-insenstivive collations. Then, if they choose case-insensitive collation for backwards compatibility, we will have to add explicit LOWER(...) or COLLATE calls to the code, to maintain the current behaviour.&lt;br /&gt;
&lt;br /&gt;
Here the risk is not just wrong sorting of reports, but it could badly break sites data integration. Hence, the risks if we get this wrong is very severe.&lt;br /&gt;
&lt;br /&gt;
We do not yet have a good solution to this problem.&lt;br /&gt;
&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Data_Item_Functions&amp;diff=64565</id>
		<title>Data Item Functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Data_Item_Functions&amp;diff=64565"/>
		<updated>2025-02-10T08:14:04Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
This page discuss the actual (sept 2006, moodle 1.7) functions used to create, modify or delete data items.&amp;lt;br&amp;gt;&lt;br /&gt;
Calculated parameters i.e {x1} are generated using the dataset parameters ( min, max, distribution) or edited directly by the teacher in the 3rd step of calculated questions creation or modification process. &lt;br /&gt;
The code for doing this,is mostly in &#039;&#039;&#039;question/type/datasetdependent/datasetitems.php&#039;&#039;&#039; and in&lt;br /&gt;
&#039;&#039;&#039;question/type/questiontype/generate_dataset_item($options)&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;question/type/questiontype/comment_on_datasetitems($question, $data, $number)&#039;&#039;&#039;&lt;br /&gt;
and backup and restore functions&lt;br /&gt;
 &lt;br /&gt;
In &#039;&#039;&#039;question/type/datasetdependent/datasetitems.php&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
// Handle adding of dataset items&lt;br /&gt;
A data item have been either generated or reused and is presented in the form so it can be edited. When the &#039;&#039;&#039;add button&#039;&#039;&#039; is clicked&lt;br /&gt;
    // This twisted condition should effectively stop resubmits caused by reloads&lt;br /&gt;
    if (isset($form-&amp;gt;addbutton) &amp;amp;&amp;amp; $maxnumber + 1 == $form-&amp;gt;numbertoadd) {&lt;br /&gt;
        $addeditem-&amp;gt;number = $form-&amp;gt;numbertoadd;&lt;br /&gt;
        foreach ($form-&amp;gt;definition as $key =&amp;gt; $defid) {&lt;br /&gt;
            $addeditem-&amp;gt;definition = $datasetdefs[$defid]-&amp;gt;id;&lt;br /&gt;
            $addeditem-&amp;gt;value = $form-&amp;gt;value[$key];&lt;br /&gt;
            if ($form-&amp;gt;itemid[$key]) {&lt;br /&gt;
                // Reuse an previously used record&lt;br /&gt;
                $addeditem-&amp;gt;id = $form-&amp;gt;itemid[$key];&lt;br /&gt;
                if (!update_record(&#039;question_dataset_items&#039;, $addeditem)) {&lt;br /&gt;
                    error(&amp;quot;Error: Unable to update dataset item&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                unset($addeditem-&amp;gt;id);&lt;br /&gt;
                if (!insert_record(&#039;question_dataset_items&#039;, $addeditem)) {&lt;br /&gt;
                    error(&amp;quot;Error: Unable to insert dataset item&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            foreach ($datasetdefs as $key =&amp;gt; $newdef) {&lt;br /&gt;
                if (isset($newdef-&amp;gt;id) &amp;amp;&amp;amp; $newdef-&amp;gt;itemcount &amp;lt;= $maxnumber) {&lt;br /&gt;
                    $newdef-&amp;gt;itemcount = $maxnumber+1;&lt;br /&gt;
                    // Save the new value for options&lt;br /&gt;
                    update_record(&#039;question_dataset_definitions&#039;, $newdef);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        // else Success:&lt;br /&gt;
        $maxnumber = $addeditem-&amp;gt;number;&lt;br /&gt;
&lt;br /&gt;
// removing of dataset items&lt;br /&gt;
&lt;br /&gt;
When the remove button is clicked&lt;br /&gt;
&lt;br /&gt;
    } else if (isset($form-&amp;gt;deletebutton)&lt;br /&gt;
               &amp;amp;&amp;amp; $maxnumber == $form-&amp;gt;numbertodelete)  {&lt;br /&gt;
        // Simply decrease itemcount where == $maxnumber&lt;br /&gt;
        foreach ($datasetdefs as $datasetdef) {&lt;br /&gt;
            if ($datasetdef-&amp;gt;itemcount == $maxnumber) {&lt;br /&gt;
                $datasetdef-&amp;gt;itemcount--;&lt;br /&gt;
                if (!update_record(&#039;question_dataset_definitions&#039;,&lt;br /&gt;
                                   $datasetdef)) {&lt;br /&gt;
                     error(&amp;quot;Error: Unable to update itemcount&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        --$maxnumber;&lt;br /&gt;
    }&lt;br /&gt;
    make_upload_directory(&amp;quot;$course-&amp;gt;id&amp;quot;);  // Just in case&lt;br /&gt;
    $grosscoursefiles = get_directory_list(&amp;quot;$CFG-&amp;gt;dataroot/$course-&amp;gt;id&amp;quot;,&lt;br /&gt;
                                       &amp;quot;$CFG-&amp;gt;moddata&amp;quot;);&lt;br /&gt;
The next form is prepared with a new or the last removed item is presented&lt;br /&gt;
&lt;br /&gt;
// Generate a new dataset item (or reuse an old one)&lt;br /&gt;
    foreach ($datasetdefs as $defid =&amp;gt; $datasetdef) {&lt;br /&gt;
        if (isset($datasetdef-&amp;gt;id)) {&lt;br /&gt;
            $datasetdefs[$defid]-&amp;gt;items = get_records_sql( // Use number as key!!&lt;br /&gt;
                    &amp;quot; SELECT number, definition, id, value&lt;br /&gt;
                      FROM {$CFG-&amp;gt;prefix}question_dataset_items&lt;br /&gt;
                      WHERE definition = $datasetdef-&amp;gt;id &amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isset($datasetdefs[$defid]-&amp;gt;items[$maxnumber + 1]) &amp;amp;&amp;amp; (&lt;br /&gt;
            empty($form-&amp;gt;forceregeneration) &amp;amp;&amp;amp;&lt;br /&gt;
            isset($form-&amp;gt;regenerateddefid) &amp;amp;&amp;amp;&lt;br /&gt;
            $form-&amp;gt;regenerateddefid != $defid ||&lt;br /&gt;
            isset($form-&amp;gt;deletebutton))) {&lt;br /&gt;
            // Reuse existing datasets&lt;br /&gt;
        } else {&lt;br /&gt;
            $datasetitem = new stdClass;&lt;br /&gt;
            $datasetitem-&amp;gt;id =&lt;br /&gt;
             isset($datasetdefs[$defid]-&amp;gt;items[$maxnumber + 1]-&amp;gt;id)&lt;br /&gt;
             ? $datasetdefs[$defid]-&amp;gt;items[$maxnumber + 1]-&amp;gt;id : &#039;&#039;;&lt;br /&gt;
            $datasetitem-&amp;gt;number = $maxnumber + 1;&lt;br /&gt;
            if ($this-&amp;gt;supports_dataset_item_generation()) {&lt;br /&gt;
                if (!empty($form-&amp;gt;addbutton) || // If we added an item&lt;br /&gt;
                    !isset($form-&amp;gt;value) ||     // If we don&#039;t have a value&lt;br /&gt;
                    $form-&amp;gt;regenerateddefid == $defid) { // If we explicitly ask for regeneration&lt;br /&gt;
                        $datasetitem-&amp;gt;value =&lt;br /&gt;
                         $this-&amp;gt;generate_dataset_item($datasetdef-&amp;gt;options);&lt;br /&gt;
                } else {&lt;br /&gt;
                    $definition = array_flip($form-&amp;gt;definition);&lt;br /&gt;
                    $datasetitem-&amp;gt;value = $form-&amp;gt;value[$definition[$defid]];&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                $datasetitem-&amp;gt;value = &#039;&#039;;&lt;br /&gt;
            }&lt;br /&gt;
            $datasetdefs[$defid]-&amp;gt;items[$maxnumber + 1] = clone($datasetitem);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
When you remove a data item, you don&#039;t delete it , you just decrease a counter in the dataset.&lt;br /&gt;
 &lt;br /&gt;
By doing it this way, this removed data item can be reused if you want it.&lt;br /&gt;
==New functions==&lt;br /&gt;
We need to create new functions that could be call by &#039;&#039;&#039;question/type/datasetdependent/datasetitems.php&#039;&#039;&#039;  and question/format.php different files.&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;function add_data_items&#039;&#039;&#039;($definition_id,$value,$data_item_id)&lt;br /&gt;
            $addeditem-&amp;gt;definition = $definition_id;&lt;br /&gt;
            $addeditem-&amp;gt;value = $value;&lt;br /&gt;
            if ($data_item_id) {&lt;br /&gt;
                // Reuse an previously used record&lt;br /&gt;
                $addeditem-&amp;gt;id = $data_item_id;&lt;br /&gt;
  // perhaps adding a check that the record exist already just in case...&lt;br /&gt;
                if (!update_record(&#039;question_dataset_items&#039;, $addeditem)) {&lt;br /&gt;
                    error(&amp;quot;Error: Unable to update dataset item&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
                unset($addeditem-&amp;gt;id);&lt;br /&gt;
                if (!insert_record(&#039;question_dataset_items&#039;, $addeditem)) {&lt;br /&gt;
                    error(&amp;quot;Error: Unable to insert dataset item&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function remove_data_items()&lt;br /&gt;
&lt;br /&gt;
function get_data_items()&lt;br /&gt;
&lt;br /&gt;
function save_data_items()&lt;br /&gt;
&lt;br /&gt;
(to be continued 1 sept 06)&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DDL_exceptions&amp;diff=64564</id>
		<title>DDL exceptions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DDL_exceptions&amp;diff=64564"/>
		<updated>2025-02-10T08:13:37Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Moodle_2.0}}In previous versions problems during upgrade were ignored by default.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
[[Image:Ddl_exceptions.png]]&lt;br /&gt;
&lt;br /&gt;
Defined in lib/ddllib.php for now.&lt;br /&gt;
&lt;br /&gt;
===ddl_exception===&lt;br /&gt;
Base class for DDL related exceptions&lt;br /&gt;
&lt;br /&gt;
===ddl_table_missing_exception===&lt;br /&gt;
Table specified in function parameter does not exist.&lt;br /&gt;
&lt;br /&gt;
===ddl_field_missing_exception===&lt;br /&gt;
Field specified in function parameter does not exist.&lt;br /&gt;
&lt;br /&gt;
===ddl_change_structure_exception===&lt;br /&gt;
General exception thrown during execution of sql that changes database structure.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Exceptions|Exceptions]]: General guidelines for using of exceptions in Moodle 2.0&lt;br /&gt;
* [[DML functions|DML functions]]: Where all the functions used to handle DB data. ([[wikipedia:Data_Manipulation_Language|DML]]) are defined.&lt;br /&gt;
* [[DDL functions|DDL functions]]: Where all the functions used to handle DB objects ([[wikipedia:Data_Definition_Language|DDL]]) are defined.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_problems&amp;diff=64563</id>
		<title>DB layer 2.0 problems</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_problems&amp;diff=64563"/>
		<updated>2025-02-10T08:13:08Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}&lt;br /&gt;
Every section on this page will show important problems present in the adoption of the new dmllib 2.0. Each section will define the problem, its impact and, when available, its solution. Every section will include one line containing its status (&#039;&#039;&#039;&#039;Open&#039;&#039;&#039;&#039;, &#039;&#039;&#039;&#039;Decided&#039;&#039;&#039;, &#039;&#039;&#039;&#039;Work in progress&#039;&#039;&#039;&#039;, &#039;&#039;&#039;&#039;Finished&#039;&#039;&#039;&#039;, &#039;&#039;&#039;&#039;Tested&#039;&#039;&#039;&#039; and &#039;&#039;&#039;&#039;Closed&#039;&#039;&#039;&#039;). &lt;br /&gt;
&lt;br /&gt;
Of course, feel free to use the [http://tracker.moodle.org Bug Tracker] to follow the daily evolution of each one of these problems by adding one link inside each section pointing to the proper bug.&lt;br /&gt;
&lt;br /&gt;
=== Do we still need record cache ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Open&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Not Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; not defined)&lt;br /&gt;
&lt;br /&gt;
::No we do not, but people must stop using get_record() in large loops (like the case of latest conditional changes in gradebook). [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]]&lt;br /&gt;
&lt;br /&gt;
=== Unknown parameter types in query parameters ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Open&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Not Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; not defined)&lt;br /&gt;
&lt;br /&gt;
We can find out the correct type of each param for inserts and updates, but in case of other queries it might be a problem :-( we could use optional type hints in parameter names like :numberI, :numberD, :nameS where IDS means int, double, string (like in mysqli driver)&lt;br /&gt;
::Wouldn&#039;t some params-&amp;gt;setInt(), setString(), setNull() do the trick? Once more the possible substitution of the plain array of values to one array of objects seems to appear in the discussion... [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 19:35, 6 May 2008 (CDT)&lt;br /&gt;
=== casting to (int) in insert_record() ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Open&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Not Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; not defined)&lt;br /&gt;
what happens if db returns string with number greater than max int?&lt;br /&gt;
:What means casting to int? Why we need that? IMO a more serious problem are some big sites raising the max int(10) sequence value (logs tables, backup and restore...). [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 19:35, 6 May 2008 (CDT)&lt;br /&gt;
::well, some code (like modedit) uses is_int() on results from insert_report() which was was breaking badly when I thied to remove the (int) casting from insert_record() [[User:Skodak|Skodak]]&lt;br /&gt;
&lt;br /&gt;
=== Do we have to use array_values() on $params array in order to re-key the array when using &amp;quot;?&amp;quot; in query? ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Open&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Not Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; not defined)&lt;br /&gt;
&lt;br /&gt;
It looks like pdo needs that [http://en.php.net/manual/en/pdostatement.execute.php]&lt;br /&gt;
&lt;br /&gt;
:: yes we must do that because the keys must be 0,1,3,... in some drivers [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]]&lt;br /&gt;
&lt;br /&gt;
=== DB layer functional tests ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;In progress&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; MDL-19057)&lt;br /&gt;
&lt;br /&gt;
reading the comments in php manual it seems like we need a big battery of unit tests to verify everything works as expected&lt;br /&gt;
:100% agree. For XMLDB stuff, for example... I&#039;ve more that &amp;quot;custom&amp;quot; tests built in the XMLDBEditor. And it only covers a few DDL commands. I guess we&#039;ll need at least.... 100 tests for good dmllib testing. [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 19:39, 7 May 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
=== persistent connections ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Open&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Not Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; not defined)&lt;br /&gt;
&lt;br /&gt;
should we limit persistent connections only for simple scripts like file.php and theme stuff? maybe this could make persistent connections more reliable. it could be implemented as some define before require config.php&lt;br /&gt;
:I would vote to include that define (CAN_USE_PERSISTENT_CONNECTION) in some files, agree. But will create one $CFG-&amp;gt;experimentwithpersistentconnections (config-dist.php) to be able to play with it in the safe side. I remember tons of headaches with persistent connections in Moodle early days (due to drivers implementation, mainly). [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 19:39, 7 May 2008 (CDT)&lt;br /&gt;
&lt;br /&gt;
=== old mysql driver ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Open&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Not Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; not defined)&lt;br /&gt;
&lt;br /&gt;
should we deprecate native mysql driver and use mysqli or pdo:mysql instead?&lt;br /&gt;
: +1 [[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 18:36, 5 May 2009 (UTC)&lt;br /&gt;
::we can remove it now completely imo [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]]&lt;br /&gt;
&lt;br /&gt;
=== ADOdb Insert_ID() function under MSSQL, using placeholders doesn&#039;t work ===&lt;br /&gt;
(&#039;&#039;&#039;Status:&#039;&#039;&#039; &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;Closed&amp;lt;/font&amp;gt; - &#039;&#039;&#039;Severity:&#039;&#039;&#039; Critical - &#039;&#039;&#039;Bug:&#039;&#039;&#039; MDL-14886)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Problem:&#039;&#039;&#039; Queries &#039;&#039;&#039;using placeholders&#039;&#039;&#039; under MSSQL are executed by one sp_executesql() procedure call. In MSSQL procedures, triggers are executed into new scopes (like &amp;quot;shells&amp;quot;), so the Insert_ID() function (internally usind SCOPE_IDENTITY()) doesn&#039;t work at all, because the insert has been executed in another scope.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Solution:&#039;&#039;&#039; Patch ADOdb driver so, each time one INSERT is going to be executed by sp_executesql(), we&#039;ll add one SCOPE_IDENTITY() in the same procedure execution (that way, both the insert and the identity will be in the same scope). Once executed, return the value of the identity by the standard Insert_ID() function. BC compatible 100% with current code if implemented that way.&lt;br /&gt;
&lt;br /&gt;
::+1 to stop using adodb and emulate bound params if needed -like in other drivers&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_migration_docs&amp;diff=64562</id>
		<title>DB layer 2.0 migration docs</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_migration_docs&amp;diff=64562"/>
		<updated>2025-02-10T08:11:25Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Much of the following documentation will not make much sense unless you first read [[XMLDB_Documentation|the XMLDB documentation]]. Please read it first if you would like to join the effort to convert Moodle&#039;s code to the new dmllib.&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to read the whole [[wikipedia:Data_Definition_Language|DDL]] and [[wikipedia:Data_Manipulation_Language|DML]] documentation before starting with the migration. That will allow you to have some initial knowledge about the new architecture.&lt;br /&gt;
&lt;br /&gt;
This article defines all the changes that need to be performed in Moodle 1.9 code in order to make it run properly under the new Moodle 2.0 DB layer. The changes below are grouped into 2 main blocks, [[XMLDB_Documentation|XMLDB]] and [[wikipedia:Data_Manipulation_Language|DML]], to keep them organised. Additional minor changes may be required in the [[wikipedia:Data_Definition_Language|DDL]] code, but won&#039;t be documented here.&lt;br /&gt;
&lt;br /&gt;
Although the order of changes shown on this page isn&#039;t mandatory at all, it can be interesting to follow the migration progress to be able to understand and learn a bit more about all them. That way, you&#039;ll end up knowing not only what to change but how and why those changes are required.&lt;br /&gt;
&lt;br /&gt;
Each change will be as simple as possible, representing one easy rule to follow to adapt the code. When anything becomes too complex to be explained as one simple rule, it will contain one link to the [[dmllib_2.0_examples|examples page]].&lt;br /&gt;
&lt;br /&gt;
For any problem in the migration of code, it&#039;s recommended to use the [http://moodle.org/mod/forum/view.php?id=55 General developer forum] at [http://moodle.org moodle.org]. Also if you find a bug in the process, please report it in the [http://tracker.moodle.org/browse/MDL-14679 Moodle Tracker], so that developers will be able to fix it ASAP.&lt;br /&gt;
&lt;br /&gt;
The Glossary module was used as the basis for many of the examples below.&lt;br /&gt;
&lt;br /&gt;
And finally, feel free to complete/fix the list below with the changes you find in the progress of migration; that will certainly help many developers. Thanks!&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== check_db_syntax: One helper script ==&lt;br /&gt;
&lt;br /&gt;
Before you start migrating your code to Moodle 2.0, it&#039;s recommended you install and run the [http://download.moodle.org/download.php/direct/tools/check_db_syntax.zip/ check_db_syntax.php] script. Simply copy it to the main folder of your plugin and execute it (from command line or via web). It will show you a list of old DB usages that need to be transformed following the information below in this article.&lt;br /&gt;
&lt;br /&gt;
If you think that something is missing in the script or have any ideas to improve it, feel free to do that yourself, commenting about it in MDL-15237. Thanks!&lt;br /&gt;
&lt;br /&gt;
Also, this (perl-compatible - works in Eclipse, hopefully elsewhere) regex:&lt;br /&gt;
&lt;br /&gt;
 (?&amp;lt;!-&amp;gt;)(?&amp;lt;!function )(?&amp;lt;!\$)\b(?:(?:count|delete|get|insert|update)_record(?!s_csv)|[gs]et_field|record_exists|execute_sql)|\$CFG-&amp;gt;prefix|rs_(?:fetch|close)|(add|strip)slashes(?!_js)&lt;br /&gt;
&lt;br /&gt;
will find most of the things in your code that need attention, with few false positives.&lt;br /&gt;
&lt;br /&gt;
== XMLDB/DDL changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
&lt;br /&gt;
* When changing DB structures it&#039;s highly recommended to use the [[XMLDB editor|XMLDB Editor]] (Admin-&amp;gt;Development-&amp;gt;XMLDB Editor). It is a safe way to edit install.xml files and to get correct PHP code to be used in upgrade.php scripts.&lt;br /&gt;
* If you have some doubts about the list of changes below, it&#039;s highly recommended to take a look at some code in core modules, blocks... whatever you need. They are a good reference.&lt;br /&gt;
* The most noticeable change (from a migration perspective) in the DDL stuff is that, starting with Moodle 2.0, we have decided to &#039;&#039;&#039;drop support for enum (check constraint) fields completely&#039;&#039;&#039;. See MDL-18577 and [http://moodle.org/mod/forum/discuss.php?d=118852 this discussion]. That implies changes in different parts of the DB stuff (XML files, function parameters, dropping existing enums...) and are commented with more detail below.&lt;br /&gt;
&lt;br /&gt;
=== The changes ===&lt;br /&gt;
* STATEMENTS section was replaced by db/install.php code and db/log.php&lt;br /&gt;
* Few other changes are required in install.xml files (that&#039;s good news!). Although you must know these:&lt;br /&gt;
** The &#039;&#039;&#039;ENUM&#039;&#039;&#039; and &#039;&#039;&#039;ENUMVALUES&#039;&#039;&#039; attributes present in your install.xml files will be completely ignored both by the DLL generation stuff and by the XMLDB Editor.&lt;br /&gt;
** In Moodle 2.1, those attributes (&#039;&#039;&#039;ENUM&#039;&#039;&#039; and &#039;&#039;&#039;ENUMVALUES&#039;&#039;&#039;) will be 100% forbidden, so it&#039;s highly recommended to erase them beginning now (Moodle 2.0).&lt;br /&gt;
** The XMLDB Editor will detect them when loading any install.xml file and will suggest you to fix that easily with one 1-click® option.&lt;br /&gt;
** No matter if you have fixed that with the 1-click® option when loading the files... the [[XMLDB editor|XMLDB Editor]] will save any edited install.xml files without those attributes.&lt;br /&gt;
** If your Moodle 1.9.x code &#039;&#039;&#039;has some enum defined in the database&#039;&#039;&#039;, you will need to create one upgrade block (in db/upgrade.php) to drop it (the enum, not the field! ;-) as part of the migration from Moodle 1.9 to 2.0 by using the new &#039;&#039;&#039;[[DB layer 2.0 examples#Dropping one enum from one field|drop_enum_from_field()]]&#039;&#039;&#039; method.&lt;br /&gt;
** Of course, if you don&#039;t use/like the XMLDB Editor, you can erase them manually with something like this:&lt;br /&gt;
 perl -p -e &#039;s/ENUM(VALUES)?=&amp;quot;.*?&amp;quot; //g&#039; &amp;lt; install.xml &amp;gt; install.xml.new&lt;br /&gt;
&lt;br /&gt;
* All upgrade.php scripts, within the main xxxx_upgrade function must have &#039;&#039;&#039;$DB&#039;&#039;&#039; (uppercase) in the globals declaration (along with others if needed). Example (from the Glossary module):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function xmldb_glossary_upgrade($oldversion=0) {&lt;br /&gt;
    &lt;br /&gt;
    global $CFG, $THEME, $DB;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* All upgrade.php scripts must NOT have &#039;&#039;&#039;$db&#039;&#039;&#039; (lowercase) in the globals declaration. Delete it if present.&lt;br /&gt;
* After the global declaration in the points above, this line must be present (we&#039;ll need it later):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$dbman = $DB-&amp;gt;get_manager(); /// loads ddl manager and xmldb classes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* All &#039;&#039;&#039;XMLDBTable&#039;&#039;&#039; instances in your upgrade code must be replaced by &#039;&#039;&#039;xmldb_table&#039;&#039;&#039; (no change in parameters)&lt;br /&gt;
* All &#039;&#039;&#039;XMLDBField&#039;&#039;&#039; instances in your upgrade code must be replaced by &#039;&#039;&#039;xmldb_field&#039;&#039;&#039; (with change in params, both $enum and $enumvalues are out from function declaration!)&lt;br /&gt;
* All &#039;&#039;&#039;XMLDBIndex&#039;&#039;&#039; instances in your upgrade code must be replaced by &#039;&#039;&#039;xmldb_index&#039;&#039;&#039; (no change in parameters)&lt;br /&gt;
* All &#039;&#039;&#039;XMLDBKey&#039;&#039;&#039; instances in your upgrade code must be replaced by &#039;&#039;&#039;xmldb_key&#039;&#039;&#039; (no change in parameters)&lt;br /&gt;
* All the &#039;&#039;&#039;addFieldInfo()&#039;&#039;&#039; methods must be replaced by &#039;&#039;&#039;add_field()&#039;&#039;&#039; (with change in params, both $enum and $enumvalues (the 7th and 8th parameters) are out from function declaration!)&lt;br /&gt;
* All the &#039;&#039;&#039;addIndexInfo()&#039;&#039;&#039; methods must be replaced by &#039;&#039;&#039;add_index()&#039;&#039;&#039; (no change in parameters)&lt;br /&gt;
* All the &#039;&#039;&#039;addKeyInfo()&#039;&#039;&#039; methods must be replaced by &#039;&#039;&#039;add_key()&#039;&#039;&#039; (no change in parameters)&lt;br /&gt;
* All the &#039;&#039;&#039;setAttributes()&#039;&#039;&#039; methods must be replaced by &#039;&#039;&#039;set_attributes()&#039;&#039;&#039; (with change in params, both $enum and $enumvalues (the 6th and 7th parameters) are out from function declaration!)&lt;br /&gt;
* All the DDL functions used in your upgrade code must be transformed as detailed below (it&#039;s simply about adding &#039;&#039;&#039;&amp;quot;$dbman-&amp;gt;&amp;quot;&#039;&#039;&#039; - without the quotes - before each function call). No changes in parameters are required:&lt;br /&gt;
** table_exists ==&amp;gt; $dbman-&amp;gt;table_exists&lt;br /&gt;
** field_exists ==&amp;gt; $dbman-&amp;gt;field_exists&lt;br /&gt;
** index_exists ==&amp;gt; $dbman-&amp;gt;index_exists&lt;br /&gt;
** find_index_name ==&amp;gt; $dbman-&amp;gt;find_index_name&lt;br /&gt;
** find_check_constraint_name ==&amp;gt; $dbman-&amp;gt;find_check_constraint_name (&#039;&#039;&#039;DEPRECATED in 2.0. OUT in 2.1&#039;&#039;&#039;)&lt;br /&gt;
** check_constraint_exists ==&amp;gt; $dbman-&amp;gt;check_constraint_exists (&#039;&#039;&#039;DEPRECATED in 2.0. OUT in 2.1&#039;&#039;&#039;)&lt;br /&gt;
** find_sequence_name ==&amp;gt; &#039;&#039;&#039;OUT in 2.0&#039;&#039;&#039;, see MDL-20349&lt;br /&gt;
** create_table ==&amp;gt; $dbman-&amp;gt;create_table&lt;br /&gt;
** drop_table ==&amp;gt; $dbman-&amp;gt;drop_table&lt;br /&gt;
** rename_table ==&amp;gt; $dbman-&amp;gt;rename_table&lt;br /&gt;
** add_field ==&amp;gt; $dbman-&amp;gt;add_field&lt;br /&gt;
** drop_field ==&amp;gt; $dbman-&amp;gt;drop field&lt;br /&gt;
** rename_field ==&amp;gt; $dbman-&amp;gt;rename_field&lt;br /&gt;
** change_field_type ==&amp;gt; $dbman-&amp;gt;change_field_type&lt;br /&gt;
** change_field_precision =&amp;gt; $dbman-&amp;gt;change_field_precision&lt;br /&gt;
** change_field_unsigned ==&amp;gt; $dbman-&amp;gt;change_field_unsigned&lt;br /&gt;
** change_field_notnull ==&amp;gt; $dbman-&amp;gt;change_field_notnull&lt;br /&gt;
** change_field_enum ==&amp;gt; $dbman-&amp;gt;change_field_enum (&#039;&#039;&#039;OUT in 2.0&#039;&#039;&#039;, see &#039;&#039;&#039;[[DB layer 2.0 examples#Dropping one enum from one field|drop_enum_from_field()]]&#039;&#039;&#039; to get rid of remaining ENUMs in code).&lt;br /&gt;
** change_field_default ==&amp;gt; $dbman-&amp;gt;change_field_default&lt;br /&gt;
** add_key ==&amp;gt; $dbman-&amp;gt;add_key&lt;br /&gt;
** drop_key ==&amp;gt; $dbman-&amp;gt;drop_key&lt;br /&gt;
** add_index ==&amp;gt; $dbman-&amp;gt;add_index&lt;br /&gt;
** drop_index ==&amp;gt; $dbman-&amp;gt;drop_index&lt;br /&gt;
* The DDL functions that change things (create/drop/rename/add)_(table/field/index) no longer return boolean. Instead, they throw an exception if they fail. So your upgrade.php no longer needs to use a &#039;&#039;&#039;$result&#039;&#039;&#039; variable, and instead should use the &#039;&#039;&#039;upgrade_mod_savepoint()&#039;&#039;&#039; function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;/** old way **/&lt;br /&gt;
if ($result &amp;amp;&amp;amp; $oldversion &amp;lt; 2008061000) {&lt;br /&gt;
    $table = new xmldb_table(&#039;facetoface_submissions&#039;);&lt;br /&gt;
    $field = new xmldb_field(&#039;notificationtype&#039;);&lt;br /&gt;
    $field-&amp;gt;set_attributes(XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;, &#039;timemodified&#039;);&lt;br /&gt;
&lt;br /&gt;
    $result = $result &amp;amp;&amp;amp; $dbman-&amp;gt;add_field($table, $field);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/** new way **/&lt;br /&gt;
if ($oldversion &amp;lt; 2008061000) {&lt;br /&gt;
    $table = new xmldb_table(&#039;facetoface_submissions&#039;);&lt;br /&gt;
    $field = new xmldb_field(&#039;notificationtype&#039;);&lt;br /&gt;
    $field-&amp;gt;set_attributes(XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;, &#039;timemodified&#039;);&lt;br /&gt;
&lt;br /&gt;
    $dbman-&amp;gt;add_field($table, $field);&lt;br /&gt;
    upgrade_mod_savepoint(true, 2008061000, &#039;facetoface&#039;);&lt;br /&gt;
}&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Finally, and not less important, your code (module, block... plugin) must guarantee that it can be upgraded &#039;&#039;&#039;ONLY&#039;&#039;&#039; from Moodle 1.9, so any previous upgrade code can be safely deleted. &#039;&#039;&#039;Moodle 2.0 requires Moodle 1.9&#039;&#039;&#039; to be upgraded, so everybody will run the 1.9 =&amp;gt; 2.0 upgrade (with other paths like 1.8 =&amp;gt; 2.0 not being possible). This is a good time to clean-up your upgrade code a bit ;-). Don&#039;t forget to take a look at the [[XMLDB editor|XMLDB Editor]] and the core modules to see how [http://cvs.moodle.org/moodle/lib/db/upgrade.php?view=markup upgrade.php] files should look in Moodle 2.0.&lt;br /&gt;
&lt;br /&gt;
== DML changes ==&lt;br /&gt;
&lt;br /&gt;
=== Some comments ===&lt;br /&gt;
* The ENTIRE CODEBASE requires an update of ALL database query function calls. Expect most moodle files to be affected by this change.&lt;br /&gt;
&lt;br /&gt;
* This is the more complex part to migrate to have the code working under Moodle 2.0, not because of the complexity of the changes themselves (90% of them will be really easy), but because you&#039;ll need to triple-check everything works as expected after changes.&lt;br /&gt;
&lt;br /&gt;
* Along the changes below, you&#039;ll find links to some examples that will try to make things easier. Anyway, if you are blocked at any point, please ask in forums or tracker (see links at the beginning of the page). Sure it has a good enough solution.&lt;br /&gt;
&lt;br /&gt;
* Once more it&#039;s highly recommended to take a look to Moodle core code, searching for similar examples. Of course, new meaningful examples are welcome, and also any clarification in the list of changes below. Feel free to do it, this is a wiki!&lt;br /&gt;
&lt;br /&gt;
* Finally, one more explanation: The changes below have been split into three sections. First one, (called &#039;&#039;&#039;&amp;quot;The golden changes&amp;quot;&#039;&#039;&#039;) are modifications that must be applied to ALL the transformations defined in the second section (&#039;&#039;&#039;&amp;quot;The iron changes&amp;quot;&#039;&#039;&#039;). Sure you&#039;ll understand that after reading them (it&#039;s basically a matter of not repeating the golden ones within each iron one, just imagine they are everywhere). Finally other changes details can be found in the &#039;&#039;&#039;&amp;quot;The tin changes&amp;quot;&#039;&#039;&#039; section.&lt;br /&gt;
&lt;br /&gt;
=== The golden changes ===&lt;br /&gt;
&#039;&#039;PLEASE read the API before going crazy with search &amp;amp; replace&#039;&#039;! You can find all the new methods in lib/dml/moodle_database.php. This is essential because some method signatures have changed (params are different), and some method names have even changed (execute_sql() is now execute()).&lt;br /&gt;
&lt;br /&gt;
Each of the golden changes below is given one short name (G1, G2, G3...) for further reference in the rest of the documentation. Let&#039;s go:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g1&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G1&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: Wherever old functions are used (get_record*, get_field*, set_field, insert_record, update_record, count_records*, delete_records, record_exists), the global $DB must be used as the object on which these functions are called (e.g. get_record_select() becomes $DB-&amp;gt;get_record_select()).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
$sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
get_record_select(&#039;user&#039;, $sql);&lt;br /&gt;
  &lt;br /&gt;
// New syntax&lt;br /&gt;
global $DB;&lt;br /&gt;
$sql = &amp;quot;WHERE id = 1&amp;quot;;&lt;br /&gt;
$DB-&amp;gt;get_record_select(&#039;user&#039;, $sql);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
::Note: for some functions, the $params array is not the second function parameter. For example, set_field:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Old syntax&lt;br /&gt;
set_field(&#039;user&#039;, &#039;firstname&#039;, &#039;Peter&#039;, &#039;id&#039;, 1);&lt;br /&gt;
  &lt;br /&gt;
// New syntax&lt;br /&gt;
global $DB;&lt;br /&gt;
$DB-&amp;gt;set_field(&#039;user&#039;, &#039;firstname&#039;, &#039;Peter&#039;, array(&#039;id&#039; =&amp;gt; 1));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g2&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G2&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: All uses of addslashes() &#039;&#039;&#039;must be removed&#039;&#039;&#039;. They are no longer needed&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g3&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G3&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: All the functions that used to accept a list of string params in the form &amp;quot;param1, value1, param2, value2&amp;quot; now need to be given an array of key=&amp;gt;value pairs as a replacement for these params. Other params remain as before. Check the new API for any exceptions.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax:&lt;br /&gt;
$user = get_record(&amp;quot;user&amp;quot;, &amp;quot;firstname&amp;quot;, &amp;quot;Peter&amp;quot;, &amp;quot;lastname&amp;quot;, &amp;quot;Cantrophus&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// New syntax:&lt;br /&gt;
global $DB;&lt;br /&gt;
$conditions = array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Peter&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Cantrophus&amp;quot;);&lt;br /&gt;
$user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, $conditions);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
::Note: The example above has been written out in full for clarity. You can use the array() directly within the function call, without using a temporary variable, if you prefer:&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$user = $DB-&amp;gt;get_record(&amp;quot;user&amp;quot;, array(&amp;quot;firstname&amp;quot; =&amp;gt; &amp;quot;Peter&amp;quot;, &amp;quot;lastname&amp;quot; =&amp;gt; &amp;quot;Cantrophus&amp;quot;) );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g4&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G4&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: rs_fetch_next_record($rs) is deprecated, in favour of the simple foreach($rs as $var). Calls to rs_close() must be replaced by $rs-&amp;gt;close();&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
while($result = rs_fetch_next_record($rs)) {&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
rs_close();&lt;br /&gt;
&lt;br /&gt;
// New syntax&lt;br /&gt;
foreach ($rs as $result) {&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
$rs-&amp;gt;close();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g5&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G5&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: Placeholders must be used for table names. Instead of {$CFG-&amp;gt;prefix}tablename, use {tablename}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
$sql = &amp;quot;SELECT * FROM {$CFG-&amp;gt;prefix}user&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// New syntax&lt;br /&gt;
$sql = &amp;quot;SELECT * FROM {user}&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g6&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G6&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: When PHP variables are used in SQL queries, they must be replaced by parameters. You have the choice between two approaches: ordered parameters, or named parameters.&lt;br /&gt;
** Ordered parameters use a simple array of values, which are given to the DML function as $params. The values in the SQL code are simply question marks (?) replacing the values. They are replaced by the DML code one by one, substituting each question mark (?) with the next value in the $params array.&lt;br /&gt;
** Named parameters use an associative array of name =&amp;gt; value pairs as the $params array. The values in the SQL code are replaced with a colon (:) followed by the key associated with the value, in the $params array. Note that named params &#039;&#039;&#039;must be unique&#039;&#039;&#039;, no matter if the value passed is the same.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
$sql = &amp;quot;SELECT id, firstname FROM {$CFG-&amp;gt;prefix}user WHERE firstname = &#039;Peter&#039; AND lastname = &#039;Cantrophus&#039;&amp;quot;;&lt;br /&gt;
$user = get_record_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
// New syntax: ordered params&lt;br /&gt;
global $DB;&lt;br /&gt;
$params = array(&#039;Peter&#039;, &#039;Cantrophus&#039;);&lt;br /&gt;
$sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = ? AND lastname = ?&amp;quot;;&lt;br /&gt;
$user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
// New syntax: named params&lt;br /&gt;
global $DB;&lt;br /&gt;
$params = array(&#039;firstname&#039; =&amp;gt; &#039;Peter&#039;, &#039;lastname&#039; =&amp;gt; &#039;Cantrophus&#039;);&lt;br /&gt;
$sql = &amp;quot;SELECT id, firstname FROM {user} WHERE firstname = :firstname AND lastname = :lastname&amp;quot;;&lt;br /&gt;
$user = $DB-&amp;gt;get_record_sql($sql, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To obtain a value for the LIKE operator, include any % signs into the parameter string. For example, code that was previously &amp;lt;tt&amp;gt;&amp;quot;LIKE &#039;$value%&#039;&amp;quot;&amp;lt;/tt&amp;gt; becomes &amp;lt;tt&amp;gt;&amp;quot;LIKE ?&amp;quot;&amp;lt;/tt&amp;gt; with the parameter &amp;lt;tt&amp;gt;$value.&#039;%&#039;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g7&amp;quot;&amp;gt;&amp;lt;b&amp;gt;G7&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: Replacement of the IN(...) syntax: We no longer hard-code this in our SQL queries, we use a function which determines whether the IN() syntax is needed, or, if there is only one value to compare, the equal (=) sign can be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax:&lt;br /&gt;
$depends_on = array(1, 43, 553);&lt;br /&gt;
$gis = implode(&#039;,&#039;, $depends_on);&lt;br /&gt;
$sql = &amp;quot;SELECT *&lt;br /&gt;
          FROM {$CFG-&amp;gt;prefix}grade_items&lt;br /&gt;
         WHERE id IN ($gis)&amp;quot;;&lt;br /&gt;
$items = $DB-&amp;gt;get_records_sql($sql);&lt;br /&gt;
  &lt;br /&gt;
// new syntax&lt;br /&gt;
global $DB;&lt;br /&gt;
$depends_on = array(1, 43, 553);&lt;br /&gt;
list($usql, $params) = $DB-&amp;gt;get_in_or_equal($depends_on);&lt;br /&gt;
$sql = &amp;quot;SELECT *&lt;br /&gt;
          FROM {grade_items}&lt;br /&gt;
         WHERE id $usql&amp;quot;;&lt;br /&gt;
$items = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; to combine the last two, do the G7 IN SQL stuff first to generate the params array, then do something like&lt;br /&gt;
  $params[&#039;firstname&#039;] = &#039;peter&#039;;&lt;br /&gt;
to add the stuff for G6&lt;br /&gt;
&lt;br /&gt;
=== The iron changes ===&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;span id=&amp;quot;I1&amp;quot;&amp;gt;&amp;lt;b&amp;gt;I1&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: Originally the &#039;&#039;&#039;sql_substr()&#039;&#039;&#039; function was used without parameters and it returned only the name of the &amp;quot;substring&amp;quot; function to be used under each DB. In Moodle 2.0 and upwards, it has 3 parameters (2 being mandatory) and it returns the complete SQL text to be used when handling substrings. Note that positions in this function are 1-based (first char has index 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
$records = get_records_sql(&amp;quot;SELECT &amp;quot; . sql_substr() . &amp;quot;(firstname, 1, 20)&amp;quot; . &amp;quot; FROM ... ...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
// New syntax&lt;br /&gt;
$records = $DB-&amp;gt;get_records_sql(&amp;quot;SELECT &amp;quot; . $DB-&amp;gt;sql_substr(&#039;firstname&#039;, 1, 20) . &amp;quot; FROM ... ...&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The tin changes ===&lt;br /&gt;
List of minor changes&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g1&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T1&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: Originally get_records() and similar functions were returning false if no records found. All these methods are now always returning arrays, empty array in case of no records found. Please note that get_record() still returns false if specified record not found.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
if (!$posts = get_records(&#039;forum_posts&#039;, &#039;parent&#039;, 666)) {&lt;br /&gt;
    $posts = array()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// New syntax&lt;br /&gt;
global $DB;&lt;br /&gt;
$posts = $DB-&amp;gt;get_records(&#039;forum_posts&#039;, array(&#039;parent&#039;=&amp;gt;666));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;g1&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T2&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;: Originally DML functions were returning &#039;&#039;false&#039;&#039; if error occurred - &#039;&#039;dml_exception&#039;&#039; is thrown now instead.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
// Old syntax&lt;br /&gt;
$record = new object();&lt;br /&gt;
$record-&amp;gt;course = 5;&lt;br /&gt;
if (!$id = insert_record(&#039;sometable&#039;, $record)) {&lt;br /&gt;
   error(&#039;can not insert new record&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// New syntax&lt;br /&gt;
global $DB;&lt;br /&gt;
$record = new object();&lt;br /&gt;
$record-&amp;gt;course = 5;&lt;br /&gt;
$id = $DB-&amp;gt;insert_record(&#039;sometable&#039;, $record);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;br /&gt;
* [[DDL exceptions|DDL exceptions]] - DDL exceptions information.&lt;br /&gt;
* [[DML exceptions|DML exceptions]] - DML exceptions information.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_implementation_plan&amp;diff=64561</id>
		<title>DB layer 2.0 implementation plan</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_implementation_plan&amp;diff=64561"/>
		<updated>2025-02-10T08:10:37Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}__NOTOC__This page contains information related to the process of development of the new xmldb/ddl/dml stuff coming with Moodle 2.0. It describes how the process has been split into some well identified milestones, and includes the summary of all the meetings and discussions about the new Moodle 2.0 DB layer.&lt;br /&gt;
&lt;br /&gt;
For a complete list of tasks related with this development you can go to MDL-14679 (everything is there). Also, don&#039;t forget to visit the [[dmllib 2.0 problems|problems page]] if you are curious about the main stoppers we have found in the project.&lt;br /&gt;
&lt;br /&gt;
Last, and not less important, the due date for all this stuff is &#039;&#039;&#039;June 24th 2008&#039;&#039;&#039;. Just in time to continue with all the rest of amazing features coming with [[Roadmap|next Moodle 2.0 release]].&lt;br /&gt;
&lt;br /&gt;
== Milestones ==&lt;br /&gt;
&lt;br /&gt;
=== M1: initial commit (due date: May 15th) - HEAD ===&lt;br /&gt;
:1. API should be stable, tested during conversion of several parts or moodle&lt;br /&gt;
:2. $db-&amp;gt; references are gone&lt;br /&gt;
:3. direct adodb function calls should be all gone (except auth and enrol)&lt;br /&gt;
:4. some functions from dmllib are deprecated/removed&lt;br /&gt;
:5. old ddllib function are not used at all now&lt;br /&gt;
:6. XMLDB editor should fully work now&lt;br /&gt;
:7. BC compatible 100%&lt;br /&gt;
&lt;br /&gt;
=== M2: 4 DBs passing all tests (due date: May 27th) - HEAD ===&lt;br /&gt;
&lt;br /&gt;
:1. mssql and ora related work&lt;br /&gt;
:2. use of adodb in enrol and auth plugins&lt;br /&gt;
:3. functional unit tests (own-db and multi-db)&lt;br /&gt;
:4. logging/profiling/exceptions&lt;br /&gt;
:5. xmldb public API refactoring&lt;br /&gt;
:6. install&lt;br /&gt;
:7. BC compatible 100%&lt;br /&gt;
:8. In general everything titled as [http://tracker.moodle.org/browse/MDL-14679 &amp;quot;M2&amp;quot; in the Bug Tracker].&lt;br /&gt;
&lt;br /&gt;
=== M3: core stuff, pre magic_quotes off tasks (due date: June 24th) - HEAD ===&lt;br /&gt;
&lt;br /&gt;
:1. Needs to be detailed in [[dmllib 2.0 migration docs|dmllib 2.0 migration docs]].&lt;br /&gt;
:2. Tasks between May28th and June 11th&lt;br /&gt;
:3. API should be available in the [http://phpdocs.moodle.org phpdocs site]&lt;br /&gt;
:4. BC compatible 100%&lt;br /&gt;
:5. In general everything titled as [http://tracker.moodle.org/browse/MDL-14679 &amp;quot;M3&amp;quot; in the Bug Tracker].&lt;br /&gt;
&lt;br /&gt;
=== M4: big hacking, post magic_quotes off tasks (due date: June 24th) - In parallel with M3 - (HEAD, BRANCH, PATCH??) ===&lt;br /&gt;
&lt;br /&gt;
:1. BREAKAGE with old code.&lt;br /&gt;
:2. Documentation finished (Docs (examples, architecture, migration guide...), PHP Docs).&lt;br /&gt;
:3. In general everything titled as [http://tracker.moodle.org/browse/MDL-14679 &amp;quot;M4&amp;quot; in the Bug Tracker].&lt;br /&gt;
&lt;br /&gt;
=== M5: Moodle tests using real &amp;amp; mockup dmllib (starting on May 27th...) - In parallel and after M3 and M4 - HEAD ===&lt;br /&gt;
&lt;br /&gt;
:1. Needs good documentation for developers&lt;br /&gt;
:2. Will be huge but useful&lt;br /&gt;
:3. Always try to be able to run tests from cli script (apart from UI) to be able to execute them daily and report status in some URL (html output).&lt;br /&gt;
&lt;br /&gt;
=== ME1: Discuss/decide/implement/test logically nested (delegated) transactions ===&lt;br /&gt;
&lt;br /&gt;
See these for more info:&lt;br /&gt;
&lt;br /&gt;
# [http://moodle.org/mod/forum/discuss.php?d=135847 moodle.org initial discussion].&lt;br /&gt;
# MDL-20625 - Bug in the Tracker with different alternatives and agreement process.&lt;br /&gt;
# [[DB layer 2.0 delegated transactions|DB layer 2.0 delegated transactions]] article in Moodle Docs, where final implementation is detailed.&lt;br /&gt;
&lt;br /&gt;
== Meetings ==&lt;br /&gt;
&lt;br /&gt;
* [http://docs.google.com/Doc?id=dgzf39jp_1gkks3pd3 MDM-20080501 Dmllib 2.0] - Penny, Petr and Eloy.&lt;br /&gt;
* [http://docs.google.com/Doc?id=dgzf39jp_5fv3j3jd7 MDM-20080508 Dmllib 2.0] - Penny, Petr, Nicolas and Eloy.&lt;br /&gt;
* [http://docs.google.com/Doc?id=dgzf39jp_7tmcr5jc5 MDM-20080513 Dmllib 2.0] - Penny, Petr, Nicolas and Eloy.&lt;br /&gt;
* [http://docs.google.com/Doc?id=dgzf39jp_11fdj3jhg8 MDM-20080515 Dmllib 2.0] - Penny, Petr, Nicolas, Martin and Eloy.&lt;br /&gt;
* [http://docs.google.com/Doc?id=dgzf39jp_12hmwjmzfq MDM-20080522 Dmllib 2.0] - Penny, Petr, Nicolas, Martin and Eloy.&lt;br /&gt;
* MDM-20080526 Dmllib 2.0 - Penny, Petr, Nicolas, Martin and Eloy.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_functional_testing&amp;diff=64560</id>
		<title>DB layer 2.0 functional testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_functional_testing&amp;diff=64560"/>
		<updated>2025-02-10T08:10:27Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}&lt;br /&gt;
&lt;br /&gt;
Functional unit tests can be used to test the interaction of Moodle and database, it is testing following:&lt;br /&gt;
* SQL database server&lt;br /&gt;
* PHP database driver&lt;br /&gt;
* Moodle DB connection settings, driver configuration and server settings&lt;br /&gt;
* Moodle DDL generator&lt;br /&gt;
* Moodle DML driver&lt;br /&gt;
&lt;br /&gt;
You can test current database specified in config.php, you can also specify other DB servers via following config.php settings, for example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;func_test_db_1 = array(&amp;quot;native&amp;quot;, &amp;quot;mysqli&amp;quot;, &amp;quot;localhost&amp;quot;, &amp;quot;root&amp;quot;, &amp;quot;yourpassword&amp;quot;, &amp;quot;moodle&amp;quot;, &amp;quot;tst_&amp;quot;, array(&#039;dbengine&#039;=&amp;gt;&#039;InnoDB&#039;));&lt;br /&gt;
$CFG-&amp;gt;func_test_db_2 = array(&amp;quot;native&amp;quot;, &amp;quot;mysqli&amp;quot;, &amp;quot;localhost&amp;quot;, &amp;quot;root&amp;quot;, &amp;quot;yourpassword&amp;quot;, &amp;quot;moodle2&amp;quot;, &amp;quot;tst_&amp;quot;, array(&#039;dbengine&#039;=&amp;gt;&#039;MyISAM&#039;));&lt;br /&gt;
$CFG-&amp;gt;func_test_db_3 = array(&amp;quot;native&amp;quot;, &amp;quot;pgsql&amp;quot;, &amp;quot;localhost&amp;quot;, &amp;quot;moodleuser&amp;quot;, &amp;quot;yourpassword&amp;quot;, &amp;quot;moodle2&amp;quot;, &amp;quot;tst_&amp;quot;, NULL);&lt;br /&gt;
$CFG-&amp;gt;func_test_db_4 = array(&amp;quot;native&amp;quot;, &amp;quot;mssql&amp;quot;, &amp;quot;192.168.15.41&amp;quot;, &amp;quot;sa&amp;quot;, &amp;quot;yourpassword&amp;quot;, &amp;quot;moodle&amp;quot;, &amp;quot;tst_&amp;quot;, NULL);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DDL tests ==&lt;br /&gt;
All DDL test must pass on any production server.&lt;br /&gt;
&lt;br /&gt;
== DML tests ==&lt;br /&gt;
Ideally all DML tests should pass on production servers.&lt;br /&gt;
&lt;br /&gt;
Common problems:&lt;br /&gt;
* MySQL MyISAM engine does ACID compliant and does not support transactions, please consider upgrading to InnoDB.&lt;br /&gt;
* MySQL supports only a limited number of collations, this may cause significant problems for non-english languages&lt;br /&gt;
* Oracle is known to fail in multiple tests (work in progress)&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_examples&amp;diff=64559</id>
		<title>DB layer 2.0 examples</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_examples&amp;diff=64559"/>
		<updated>2025-02-10T08:09:50Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}__NOTOC__&lt;br /&gt;
&lt;br /&gt;
=== Dropping one enum from one field ===&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0, we have &#039;&#039;&#039;discontinued support for ENUM&#039;&#039;&#039; (check constraint) in DB columns. See MDL-18577 about that. So, any plugin using enums in Moodle 1.9 will need to drop them as part of the upgrade to Moodle 2.0. To achieve that, as commented in the [[DB layer 2.0 migration docs#XMLDB/DDL changes|migration docs]], the &#039;&#039;&#039;drop_enum_from_field()&#039;&#039;&#039; method will be used. Here it&#039;s one &#039;&#039;&#039;real&#039;&#039;&#039; example used to drop the enum defined in the forum-&amp;gt;type column as part of the upgrade from Moodle 1.9 to 2.0 (just adjust it for your own needs):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/// Dropping all enums/check contraints from core. MDL-18577&lt;br /&gt;
    if ($result &amp;amp;&amp;amp; $oldversion &amp;lt; 2009042700) {&lt;br /&gt;
&lt;br /&gt;
    /// Changing list of values (enum) of field type on table forum to none&lt;br /&gt;
        $table = new xmldb_table(&#039;forum&#039;);&lt;br /&gt;
        $field = new xmldb_field(&#039;type&#039;, XMLDB_TYPE_CHAR, &#039;20&#039;, null, XMLDB_NOTNULL, null, &#039;general&#039;, &#039;course&#039;);&lt;br /&gt;
&lt;br /&gt;
    /// Launch change of list of values for field type&lt;br /&gt;
        $dbman-&amp;gt;drop_enum_from_field($table, $field);&lt;br /&gt;
&lt;br /&gt;
    /// forum savepoint reached&lt;br /&gt;
        upgrade_mod_savepoint($result, 2009042700, &#039;forum&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mixing query params and IN params ===&lt;br /&gt;
&lt;br /&gt;
As you know, in Moodle 2.0 we are using placeholders for all the parameters passed to any SQL statement (see [[DB layer 2.0 migration docs#g6|G6]]. Also, we use one special function to convert any list of values to the proper IN/EQUAL clause and associated params (see [[DB layer 2.0 migration docs#g7|G7]]).&lt;br /&gt;
&lt;br /&gt;
But what happens when we want to mix both type of params (query params and IN params) in the same query? Here it&#039;s one example:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Objective:&#039;&#039;&#039; return the number of forum discussion per course belonging to a given list of courses (IN params) and one type of forum (query param).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/// Here it&#039;s the query param (we are looking for &#039;general&#039; forums in this example)&lt;br /&gt;
    $queryparams = array(&#039;general&#039;);&lt;br /&gt;
&lt;br /&gt;
/// Here we calculate the IN clause (the list of courses we are going to search)&lt;br /&gt;
/// it returns 2 values: the SQL IN clause needed and the params array to be applied&lt;br /&gt;
    list($insql, $inparams) = $DB-&amp;gt;get_in_or_equal(array(1, 2, 3, 4, 5, 6));&lt;br /&gt;
&lt;br /&gt;
/// Here it&#039;s the query we are going to execute, with the IN clause injected in place&lt;br /&gt;
    $sql = &amp;quot;SELECT f.course, COUNT(*) count&lt;br /&gt;
              FROM {forum} f&lt;br /&gt;
              JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
             WHERE f.type = ?&lt;br /&gt;
                   AND f.course $insql&lt;br /&gt;
          GROUP BY f.course&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
/// Here we merge all params (query ones and IN clause ones,&lt;br /&gt;
/// respecting the order they are used in the query!)&lt;br /&gt;
    $params = array_merge($queryparams, $inparams);&lt;br /&gt;
&lt;br /&gt;
/// Execute the query, returning the expected count per course&lt;br /&gt;
    $records = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that &#039;&#039;&#039;is really important to respect the order of the params&#039;&#039;&#039; when merging them in case you are using question mark placeholders in your query. Alternatively, you can use named params if you want to skip that ordering potential issue, specially if your query is very complex or highly dynamic. Here it&#039;s the same example using named params (see the 2nd param used in the get_in_or_equal() method call), that&#039;s all :&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/// Here it&#039;s the query param (we are looking for &#039;general&#039; forums in this example)&lt;br /&gt;
    $queryparams = array(&#039;forum_type&#039; =&amp;gt; &#039;general&#039;);&lt;br /&gt;
&lt;br /&gt;
/// Here we calculate the IN clause (the list of courses we are going to search)&lt;br /&gt;
/// it returns 2 values: the SQL IN clause needed and the params array to be applied&lt;br /&gt;
    list($insql, $inparams) = $DB-&amp;gt;get_in_or_equal(array(1, 2, 3, 4, 5, 6), SQL_PARAMS_NAMED);&lt;br /&gt;
&lt;br /&gt;
/// Here it&#039;s the query we are going to execute, with the IN clause injected in place&lt;br /&gt;
    $sql = &amp;quot;SELECT f.course, COUNT(*) count&lt;br /&gt;
              FROM {forum} f&lt;br /&gt;
              JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
             WHERE f.type = :forum_type&lt;br /&gt;
                   AND f.course $insql&lt;br /&gt;
          GROUP BY f.course&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
/// Here we merge all params (query ones and IN clause ones,&lt;br /&gt;
/// as we are using named params, order isn&#039;t important)&lt;br /&gt;
    $params = array_merge($inparams, $queryparams);&lt;br /&gt;
&lt;br /&gt;
/// Execute the query, returning the expected count per course&lt;br /&gt;
    $records = $DB-&amp;gt;get_records_sql($sql, $params);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[Database|Database coding guidelines]]: where some basic rules to follow are defined.&lt;br /&gt;
* [[DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_delegated_transactions&amp;diff=64558</id>
		<title>DB layer 2.0 delegated transactions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0_delegated_transactions&amp;diff=64558"/>
		<updated>2025-02-10T08:09:33Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}__NOTOC__&lt;br /&gt;
=== General principles ===&lt;br /&gt;
&lt;br /&gt;
# Everybody thinks it&#039;s a good idea to have those logical nested transactions in Moodle (but me and ML)&lt;br /&gt;
# No matter of they nested nature, they are really &#039;&#039;&#039;&amp;quot;delegated transactions&amp;quot;&#039;&#039;&#039; (so outer levels get the control over inner ones), so we are going to apply that naming to enforce the real concept.&lt;br /&gt;
# Code will &#039;&#039;&#039;never&#039;&#039;&#039; rely on rollback happening. it&#039;s only a maeasure to reduce (not to eliminate) DB garbled information.&lt;br /&gt;
# Any problem related with the use of transactions (unfinished ones,  unbalanced, finished twice...) will end &#039;&#039;&#039;always&#039;&#039;&#039; with one transaction_exception that will &#039;&#039;&#039;always&#039;&#039;&#039; end performing one DB rollback.  &lt;br /&gt;
# If one transaction (at any level) has been marked for rollback() there won&#039;t be any method to change it. Finally Moodle will perform the DB rollback.&lt;br /&gt;
# If one transaction (at any level) has been marked for commit() it will be possible to change that status to rollback() in any outer level.&lt;br /&gt;
# It will be &#039;&#039;&#039;optional&#039;&#039;&#039; to catch exceptions when using transactions, but if they are caught, then it&#039;s mandatory to mark the transaction for rollback()&lt;br /&gt;
# Any explicit rollback() call will pass the exception originating it, i.e. rollback($exception) to be re-thrown.&lt;br /&gt;
# API will work in a natural and similar fashion to current recordsets one.&lt;br /&gt;
# We&#039;ll start &#039;&#039;&#039;recommending&#039;&#039;&#039; to use InnoDB for 2.0 in environmental tests. Posibly, at some point in the future that will become a &#039;&#039;&#039;must&#039;&#039;&#039;. But &#039;&#039;&#039;it is not&#039;&#039;&#039; for now (be warned!).&lt;br /&gt;
&lt;br /&gt;
=== The API ===&lt;br /&gt;
&lt;br /&gt;
# All the handling must go, exclusively, to moodle_database object, leaving real drivers only implementing (protected) the old begin/commit/rollback_sql() functions.&lt;br /&gt;
# One array of objects of type moodle_delegated_transaction will be stored / checked from $DB&lt;br /&gt;
# $DB will be the responsible to instantiate / accumulate / pair / compare moodle_delegated_transactions&lt;br /&gt;
# Each moodle_transaction will be able to set the global mark for rollback. Commit won&#039;t change anything.&lt;br /&gt;
# Inner-most commit/rollback will printout one complete stack of moodle_transactions information if we are under DEBUG_DEVELOPER and new setting (delegatedtransactionsdebug) is enabled.&lt;br /&gt;
# Normal usage of the moodle_transaction will be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$transaction = $DB-&amp;gt;start_delegated_transaction();&lt;br /&gt;
// Perform some $DB stuff&lt;br /&gt;
$transaction-&amp;gt;allow_commit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
7. If, for any reason, developer needs to catch exceptions when using transactions, it will be mandatory to use it in this way:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
    $transaction = $DB-&amp;gt;start_delegated_transaction();&lt;br /&gt;
    // Perform some $DB stuff&lt;br /&gt;
    $transaction-&amp;gt;allow_commit();&lt;br /&gt;
} catch (Exception $e) {&lt;br /&gt;
    //extra cleanup steps&lt;br /&gt;
    $transaction-&amp;gt;rollback($e); // rethrows exception&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
8. In order to be able to keep some parts of code out from top transactions completely, if we know it can lead to problems, we can use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $DB-&amp;gt;transactions_forbidden(); // Instant check to confirm we aren&#039;t using transactions in this point. Will throw exception if transaction is found.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===The Flow===&lt;br /&gt;
&lt;br /&gt;
[[Image:TransactionsAndExceptionsFlow.png|thumb|right|caption]]&lt;br /&gt;
# Any default exception handler will:&lt;br /&gt;
## Catch uncaught transaction_exception exceptions, &lt;br /&gt;
## Properly perform the DB rollback&lt;br /&gt;
## debug/error/log honouring related settings.&lt;br /&gt;
## inform with as many details as possible (token, place... whatever).&lt;br /&gt;
# Any &amp;quot;footer&amp;quot; (meaning some place before ending &amp;lt;html&amp;gt; output) will:&lt;br /&gt;
## Detect &amp;quot;in-transaction&amp;quot; status.&lt;br /&gt;
## Let execution continue, transaction is automatically rolled back in $DB-&amp;gt;dispose()&lt;br /&gt;
## inform with as many details as possible (token, place... whatever).&lt;br /&gt;
# $DB-&amp;gt;dispose() will:&lt;br /&gt;
## Detect &amp;quot;in-transaction&amp;quot; status.&lt;br /&gt;
## log error (not possible to honour settings!)&lt;br /&gt;
## Properly perform the full DB rollback&lt;br /&gt;
&lt;br /&gt;
===Related tasks===&lt;br /&gt;
&lt;br /&gt;
# Move this to MoodleDocs and publicy in Dev Forum.&lt;br /&gt;
# Implement fulfilling current specs / review / test iterations&lt;br /&gt;
# Re-enforce in Docs, phpdocs, everywhere, the &amp;quot;Code will *never* rely on rollback happening&amp;quot; and the &amp;quot;delegated&amp;quot; nature of the whole thing.&lt;br /&gt;
# Be extremely careful about any use of delegated transactions until we get used to them, reviewing them in core often.&lt;br /&gt;
# Point somewhere about the move to InnoDB, pros/cons, migration process... to have it documented.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=DB_layer_2.0&amp;diff=64557</id>
		<title>DB layer 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=DB_layer_2.0&amp;diff=64557"/>
		<updated>2025-02-10T08:09:00Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Template:Development:dmllib 2.0}}{{Moodle_2.0}}__NOTOC__&lt;br /&gt;
== Objectives ==&lt;br /&gt;
&lt;br /&gt;
* Switch to prepared statements - using placeholders and preparing statements protects against sql injection&lt;br /&gt;
* Remove the need for data to be add/strip slashed all over the place in the code.&lt;br /&gt;
* Enable easier and productive unit tests.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
* 100% cross-db&lt;br /&gt;
* OOP implementation:&lt;br /&gt;
** Full abstraction: Hide underlying libraries (adodb, pdo...) and drivers to Moodle developers completely.&lt;br /&gt;
** Make it so that the database object can be subclassed - this means for unit tests that want to test database access, the test framework can override necessary methods&lt;br /&gt;
** support ? and :param parameter types (independently of the param types supported by each driver).&lt;br /&gt;
** global $DB&lt;br /&gt;
** profiling, logging and exceptions&lt;br /&gt;
* Easy to use (consistent and similar to current dmllib 1.0)&lt;br /&gt;
* Easy to migrate (provide documentation and utilities to help on that)&lt;br /&gt;
* Complete unit testing (self)&lt;br /&gt;
* Easy unit testing (moodle - real and mockup)&lt;br /&gt;
* Well documented (PHPDocs + use examples)&lt;br /&gt;
* Tasks, bugs and progress tracked in MDL-14679&lt;br /&gt;
* Due date: June 24th 2008&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[XMLDB Documentation|XMLDB Documentation]]: where both xmldb and ddl stuff is explained.&lt;br /&gt;
* [[DDL functions|DDL functions]] - Documentation for all the Data Definition Language (DDL) functions available inside Moodle.&lt;br /&gt;
* [[DML functions|DML functions]] - Documentation for all the Data Manipulation Language (DML) functions available inside Moodle.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Customizing_Moodle&amp;diff=64556</id>
		<title>Customizing Moodle</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Customizing_Moodle&amp;diff=64556"/>
		<updated>2025-02-10T08:08:09Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
Many of us have been making small modifications to our Moodle installs, and this is the place to share them.  Please take care with any of these modifications - they may have not been widely tested!  Be sure to back up your files and database if required.&lt;br /&gt;
&lt;br /&gt;
*[[Hard-coded Variables]]&lt;br /&gt;
&lt;br /&gt;
*[[Course Approval]]&lt;br /&gt;
*[[Front Page]]&lt;br /&gt;
*[[Maintaining Moodle with Dreamweaver]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Customisable_user_profiles&amp;diff=64555</id>
		<title>Customisable user profiles</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Customisable_user_profiles&amp;diff=64555"/>
		<updated>2025-02-10T08:06:34Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The main goal is to allow administrators to add/edit user profile fields. These fields may also be categorised, ordered, locked, hidden.&lt;br /&gt;
&lt;br /&gt;
== Database Changes ==&lt;br /&gt;
&lt;br /&gt;
=== New tables ===&lt;br /&gt;
&lt;br /&gt;
There are 3 new tables:&lt;br /&gt;
* &#039;&#039;&#039;user_info_field&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;user_info_category&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;user_info_data&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Splitting the current user table ===&lt;br /&gt;
In version 2.0, the following fields will be moved from the &#039;&#039;&#039;user&#039;&#039;&#039; table and placed in a category named &#039;&#039;&#039;optional&#039;&#039;&#039;&lt;br /&gt;
*icq&lt;br /&gt;
*skype&lt;br /&gt;
*yahoo&lt;br /&gt;
*aim&lt;br /&gt;
*msn&lt;br /&gt;
*phone1&lt;br /&gt;
*phone2&lt;br /&gt;
*institution&lt;br /&gt;
*department&lt;br /&gt;
*address&lt;br /&gt;
*url&lt;br /&gt;
&lt;br /&gt;
The remaining fields will remain hardcoded in the user profile form.&lt;br /&gt;
&lt;br /&gt;
== Admin&#039;s Interface ==&lt;br /&gt;
&lt;br /&gt;
=== Various field flags ===&lt;br /&gt;
*&#039;&#039;&#039;required&#039;&#039;&#039; - a required field. Fields marked as required will also be displayed in the signup form;&lt;br /&gt;
*&#039;&#039;&#039;locked&#039;&#039;&#039; - can the user edit this field?;&lt;br /&gt;
*&#039;&#039;&#039;unique&#039;&#039;&#039; - the data entered must be unique;&lt;br /&gt;
*&#039;&#039;&#039;signup&#039;&#039;&#039; - the field should appear on the signup page;&lt;br /&gt;
*&#039;&#039;&#039;visible&#039;&#039;&#039; - can the user see this field? Options are:&lt;br /&gt;
**&#039;&#039;&#039;Not visible&#039;&#039;&#039; - only a site administrator can see and edit this field&lt;br /&gt;
**&#039;&#039;&#039;Visible to user&#039;&#039;&#039; - information is private to the user&lt;br /&gt;
**&#039;&#039;&#039;Visible to everyone&#039;&#039;&#039; - information is available to anyone who can view user profiles&lt;br /&gt;
&lt;br /&gt;
=== Adding/Editing fields ===&lt;br /&gt;
&lt;br /&gt;
[[Image:siteadmin_customprofiles.jpg|Link to the custom profiles interface from the site administration block]]&lt;br /&gt;
&lt;br /&gt;
==== Steps ====&lt;br /&gt;
* 1. Make a category&lt;br /&gt;
** For example: &amp;quot;Class Information&amp;quot;&lt;br /&gt;
** Then in the lower left-hand part of the page, you&#039;ll see &amp;quot;Create a new profile field:.&amp;quot;&lt;br /&gt;
* 2. Choose: &amp;quot;Menu of choices&amp;quot;&lt;br /&gt;
** Example: Enter &amp;quot;p-teacher&amp;quot; then &amp;quot;Teacher&amp;quot; then a list of teachers who teach a given course.&lt;br /&gt;
** Example: Enter &amp;quot;p-major&amp;quot; then &amp;quot;Major&amp;quot; then a list of the majors offered at your school&lt;br /&gt;
* 3. Make another category,  for example: &amp;quot;Personal Info&amp;quot;&lt;br /&gt;
* 4.  Choose: &amp;quot;Text&amp;quot;&lt;br /&gt;
** Example: Enter &amp;quot;p-hobby&amp;quot; then &amp;quot;Hobbies&amp;quot;&lt;br /&gt;
** Example: Enter &amp;quot;p-birthday&amp;quot; then &amp;quot;Birthday&amp;quot;&lt;br /&gt;
* 5. Now go to your own profile and click the &amp;quot;edit profile&amp;quot; tab to see how it looks.&lt;br /&gt;
&lt;br /&gt;
== User&#039;s Interface ==&lt;br /&gt;
&lt;br /&gt;
=== User profile page ===&lt;br /&gt;
&lt;br /&gt;
=== The signup page ===&lt;br /&gt;
The signup form will be changed to include all required custom profile fields.&lt;br /&gt;
&lt;br /&gt;
=== The &amp;quot;public&amp;quot; user profile page ===&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[:en:User profile fields|User profile fields]] for administrators&lt;br /&gt;
*Using Moodle [http://moodle.org/mod/forum/discuss.php?d=55814 Should I hack the mdl_user table, or add my own?] forum discussion&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_search&amp;diff=64554</id>
		<title>Course search</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_search&amp;diff=64554"/>
		<updated>2025-02-10T08:05:53Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Work_in_progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Course search&lt;br /&gt;
|state = Community bonding period&lt;br /&gt;
|tracker = CONTRIB-4335&lt;br /&gt;
|discussion = [https://moodle.org/mod/forum/discuss.php?d=230469 Writing Moodle&#039;s Course Search plugin]&lt;br /&gt;
[https://moodle.org/mod/forum/discuss.php?d=232803 Course Search plugin Progress]&lt;br /&gt;
|assignee = [https://moodle.org/user/profile.php?id=1565325 Shashikant Vaishnav]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;GSOC&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt; &#039;13&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Object of this google summer of code project is to Implement Advanced Course Search that is flexible, case-insensitive, fast and can sort results by relevance. Most importantly it should work consistently on different Database engines and different content languages. The deliverable includes a functional advance search plugin for Moodle that can be installed and configured to substitute basic core search. The project will be implemented integrating 3rd party search engine API with Moodle course schema.&lt;br /&gt;
&lt;br /&gt;
== Problem Description ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Non latin support with search queries:&#039;&#039;&#039; Database engines don&#039;t recognize word boundaries in non-english languages and can&#039;t do case-insensitive search.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Indexing:&#039;&#039;&#039; We don&#039;t want to reinvent the wheel as there are many awesome open source enterprise level search indexers available that can make our course search fast and efficient.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sorting by relevance:&#039;&#039;&#039; We need to sort results according to relevance for example if a query result matches course name then it&#039;s more relevant then its other matches with summary of course. Implementing spelling correction (Did you mean?) feature. Also fuzzy search (alternate form of words) needs to be implemented.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Work consistently on different database engines and different content language:&#039;&#039;&#039; Course search should be implemented in a way that it can deal with as many databases possible. and it should be able to deal with different content language.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* works consistently on different DB engines and different content languages( Non latin languages support)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Search results with relevance( Score )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Case insensitive search capability&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Searchable Document Formats&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  * Hyper Text Markup Language&lt;br /&gt;
  * XML and derived formats&lt;br /&gt;
  * Microsoft Office document formats&lt;br /&gt;
  * Open Document Format&lt;br /&gt;
  * Portable Document Format &lt;br /&gt;
  * Rich Text Format&lt;br /&gt;
  * Compression and packaging formats [See Rebuilding Solr Cell]&lt;br /&gt;
  * Text formats&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Autocomplete ( autosuggest with non-latin languages too )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Very fast than existing course search implementation. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Spell Checking capability ( Did you mean ?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Keyword Matching (Searching within specific field)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    Example :- &amp;quot;summary:Getting started with python&amp;quot; searches for the &amp;quot;Getting started with python&amp;quot; in summary field of courses.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Proximity Search&lt;br /&gt;
&lt;br /&gt;
    Example :- &amp;quot;moodle perth&amp;quot;~4 Search for &amp;quot;moodle perth&amp;quot; within 4 words from each other.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Wildcard Search&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Fuzzy search support ( Alternate form of words )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Filtering results by startdate (Range queries)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Pagination &amp;amp; sorting results by relevance, startdate, shortname.&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
Earlier we had two choices for this purpose - Apache Solr and Sphinx. Both Apache solr and Sphinx has extensive documentation and community support and have very powerful indexing capabilities, but eventually faceted search and fuzzy search features that works out of the box with some other key points explained below for Apache Solr made it the winning solution.&lt;br /&gt;
&lt;br /&gt;
=== Why Apache Solr ===&lt;br /&gt;
&lt;br /&gt;
*  As in Courses we are going to deal with Different types of summary documents &amp;amp; Solr can index proprietary formats like Microsoft Word, Pdf, etc. Sphinx can&#039;t.&lt;br /&gt;
&lt;br /&gt;
*  Solr supports field collapsing to avoid duplicating similar results. Sphinx doesn&#039;t seem to provide any feature like this.&lt;br /&gt;
&lt;br /&gt;
*  As we were concerned about the non-latin character support, Solr supports unicode character search out of the box.&lt;br /&gt;
&lt;br /&gt;
*  Solr, being an Apache project, is obviously Apache2-licensed. So the real challenge is now to integrate Apache Solr with moodle course search functionality. Advance course search will be installed as a plugin to substitute basic core search.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Project Roadmap ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Preparing course search schema to integrate with Apache solr :&#039;&#039;&#039; Solr reads the schema to be indexed using a xml based configuration file, lets call it schema.xml. When user will install advance search plugin, it will contain its schema file that will be automatically replaced by the corresponding files located on the Solr server, and it can usually be found in the main Solr directory solr/conf. We will need to design moodle course search schema.xml depending on what fields we want to index and how. Available field types and filter options in Solr makes it very flexible how we want to do that. Fortunately similar problem has already been sorted out by Drupal folks and I am quite familiar with that so here we can use this knowledge reference. Searchable fields in course are idnumber, shortname, fullname, summary. We will start with these fields for designing the schema for moodle course search.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Extending apache Solr integration library with php to work with moodle :&#039;&#039;&#039; It is the Solr Php Client library that will talk between moodle and Solr. Here we need to extend these files to make it work with moodle course search plugin.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Indexing the course search data:&#039;&#039;&#039; The entry point of indexing courses is the Cron task. Whenever the cron will run, an associated callback will trigger the indexing procedure. The plugin will look for courses which are marked for indexing, then for each course an object that contains all the relevant field contents to be indexed, will be individually converted into XML query and sent to the Solr server for indexing. We can also create a custom event to notify other entities that we just performed an indexing operation. How much courses can be indexed at once can be an admin setting. On admin side we will also have means to mark a course as a candidate for reindexing, so -&lt;br /&gt;
&lt;br /&gt;
*    We need to perform re-indexing(by Cron listening)&lt;br /&gt;
          - If a new coursed is created. &lt;br /&gt;
&lt;br /&gt;
          - If a existing course is deleted or updated.&lt;br /&gt;
&lt;br /&gt;
          - Or it is marked by admin to index again&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Plugin search API functions :&#039;&#039;&#039; Internal search API functions will  have these objectives -&lt;br /&gt;
&lt;br /&gt;
1. Getting the basic search query via form submission&lt;br /&gt;
&lt;br /&gt;
2. Translation of this search query into appropriate Apache Solr query and adding appropriate parameters for extra search options&lt;br /&gt;
&lt;br /&gt;
3. Trigger the search by sending this query to locally running Apache Solr instance&lt;br /&gt;
&lt;br /&gt;
4. Getting the search response and rendering the search results via proper theme function.&lt;br /&gt;
&lt;br /&gt;
As we know Advance search is plugin type code base so when installed it will overtake the responsibility of search system. So when the user activates advance search plugin, then moodle will interact with its internal search and to interact with apache solr in backend. These search functions will be responsible to &#039;generate&#039; the required apache solr query and to speak with solr running instance.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;On caching -&#039;&#039;&#039; While retrieving the list of courses that match search string Apache Solr has the mechanism to cache repetitious search queries. It has two built-in in-memory caches. one for search results and one for documents. They are typically limited to several thousands entries each.&lt;br /&gt;
&lt;br /&gt;
Finally we will prepare the list of courses to show to the user, with filtering out hidden courses that user can not see, retrieve all additional information such as category name, course contacts, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Achieving relevancy by using Solr&#039;s awesome faceted search feature:&#039;&#039;&#039; We can achieve relevancy by dynamic filtering results like searching start date(by days,months,years etc.) or spelling correct feature (Did you mean?) and in back-end Solr supports that out of box.&lt;br /&gt;
&lt;br /&gt;
Relevancy is made using the &#039;&#039;boost&#039;&#039; clause on the field you want to give higher relevance. These &amp;quot;boost&amp;quot; clause will be added on search fields by internal search API functions as per the need while generating the search query for Apache Solr. From the Solr docs I found these key points to achieve for relevant results.[2]&lt;br /&gt;
&lt;br /&gt;
By default Apache solr sorts given search results in order of relevancy, and relevancy is defined in terms of how much &#039;boost&#039; we have given to particular field and if some field has to remain more relevant by default than other Apache Solr by altering the schema file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Solr with alternate form of words(fuzzy search):-&#039;&#039;&#039; In Apache Solr Text fields are typically indexed by breaking the text into words and applying various transformations such as lower casing  removing plurals, or stemming to increase relevancy. The same text transformations are normally applied to any queries in order to match what is indexed.So when you are searching for &amp;quot;Fly&amp;quot; it also looks for &amp;quot;Flies&amp;quot; or &amp;quot;Flew&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
*  &#039;&#039;&#039;Solr with intra-word delimiters:-&#039;&#039;&#039; The filter &#039;WordDelimiterFilter&#039; can be used in the analyzer for the field being queried to match words with intra-word delimiters such as dashes or case changes. By default apache solr provides lots of filters for text field type to configure these things. Properly configured schema.xml is the key point to handle this.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisite ===&lt;br /&gt;
&lt;br /&gt;
Java 5 or higher (a.k.a. 1.5.x), PHP 5.1.4 or higher, moodle 2.5 or higher.&lt;br /&gt;
&lt;br /&gt;
=== Installing admin tool ===&lt;br /&gt;
&lt;br /&gt;
1. Download the admin tool from here. (https://moodle.org/plugins/view.php?plugin=tool_coursesearch) &lt;br /&gt;
&lt;br /&gt;
2. Extract the Course Search folder. Put it under moodle installation/admin/tool directory.&lt;br /&gt;
&lt;br /&gt;
3. It should be named coursesearch. If you are already logged in just refreshing the browser should trigger your moodle &lt;br /&gt;
site to begin the install &#039;Plugins Check&#039;.&lt;br /&gt;
&lt;br /&gt;
4. If not then navigate to Administration &amp;gt; Notifications.&lt;br /&gt;
&lt;br /&gt;
=== Installing search_cleantheme OR replacing/copying the renderer.php file ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here is two options either you may replace/copy your existing theme renderer with the one found in&lt;br /&gt;
search_cleantheme(https://github.com/shashirepo/moodle-theme_cleantheme).&lt;br /&gt;
OR you may install cleantheme itself.&lt;br /&gt;
&lt;br /&gt;
replacing /copying the renderer file to your theme.&lt;br /&gt;
&lt;br /&gt;
1. Copy renderer.php file from search_cleantheme replace it with your theme&#039;s renderer file.&lt;br /&gt;
&lt;br /&gt;
2. Standard moodle theme doesn&#039;t have any renderer file so you may simply copy this to your&lt;br /&gt;
theme directory.&lt;br /&gt;
&lt;br /&gt;
3. Rename renderer class name according to your theme name.&lt;br /&gt;
&lt;br /&gt;
for example if you are using theme &#039;clean&#039;.&lt;br /&gt;
then rename the class names to &#039;theme_clean_core_renderer&#039; &amp;amp; &#039;theme_clean_core_course_renderer&#039;.&lt;br /&gt;
&lt;br /&gt;
OR you may either use search_cleantheme. This is based on bootstrap clean theme.&lt;br /&gt;
&lt;br /&gt;
1. Download the cleantheme from here (https://github.com/shashirepo/moodle-theme_cleantheme) &lt;br /&gt;
&lt;br /&gt;
2. Extract the theme folder. and put it under moodle installation theme directory.&lt;br /&gt;
&lt;br /&gt;
3. If you are already logged in just refreshing the browser should trigger your Moodle&lt;br /&gt;
site to begin the install &#039;Plugins Check&#039;.&lt;br /&gt;
&lt;br /&gt;
4. If not then navigate to Administration &amp;gt; Notifications.&lt;br /&gt;
&lt;br /&gt;
=== Installing Solr &amp;amp; placing the plugin Schema ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Download the latest Solr 4.4.0 release from:&lt;br /&gt;
http://lucene.apache.org/solr/&lt;br /&gt;
&lt;br /&gt;
Unpack the tarball somewhere not visible to the web (not in your apache docroot&lt;br /&gt;
and not inside of your moodle directory).&lt;br /&gt;
&lt;br /&gt;
The Solr download comes with an example application that you can use for&lt;br /&gt;
testing, development, and even for smaller production sites. This&lt;br /&gt;
application is found at apache-solr-4.4.0/example.&lt;br /&gt;
&lt;br /&gt;
Move apache-solr-4.4.0/example/solr/collection1/conf/schema.xml and rename it to&lt;br /&gt;
something like schema.bak. Then move the schema.xml that comes &lt;br /&gt;
with moodle course search admin tool plugin to take its place.&lt;br /&gt;
&lt;br /&gt;
Similarly, move apache-solr-4.4.0/example/solr/collection1/conf/solrconfig.xml and rename&lt;br /&gt;
it like solrconfig.bak. Then move the solrconfig.xml that comes with the&lt;br /&gt;
moodle course search admin tool plugin to take its place.&lt;br /&gt;
&lt;br /&gt;
Finally, move apache-solr-4.4.0/example/solr/collection1/conf/protwords.txt and rename&lt;br /&gt;
it like protwords.bak. Then move the protwords.txt that comes with the&lt;br /&gt;
moodle course search admin tool plugin  to take its place.&lt;br /&gt;
&lt;br /&gt;
Make sure that the conf directory includes the following files - the Solr core&lt;br /&gt;
may not load if you don&#039;t have at least an empty file present:&lt;br /&gt;
solrconfig.xml&lt;br /&gt;
schema.xml&lt;br /&gt;
elevate.xml&lt;br /&gt;
mapping-ISOLatin1Accent.txt&lt;br /&gt;
protwords.txt&lt;br /&gt;
stopwords.txt&lt;br /&gt;
synonyms.txt&lt;br /&gt;
&lt;br /&gt;
Now start the solr application by opening a shell, changing directory to&lt;br /&gt;
apache-solr-4.4.0/example, and executing the command java -jar start.jar&lt;br /&gt;
&lt;br /&gt;
Test that your solr server is now available by visiting&lt;br /&gt;
http://localhost:8983/solr/admin/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Testing with ping to solr ===&lt;br /&gt;
&lt;br /&gt;
1. Advance Course can be found under :-&lt;br /&gt;
&lt;br /&gt;
Administration-&amp;gt;course-&amp;gt;Course search settings(URL:- http://127.0.0.1/MoodleInstalltionURL/admin/tool/coursesearch)&lt;br /&gt;
&lt;br /&gt;
2. Give the solr configuration options here:-&lt;br /&gt;
&lt;br /&gt;
Solr Host:- localhost or 127.0.0.1&lt;br /&gt;
Solr Port:- 8983 (Default port for Solr )&lt;br /&gt;
Solr path :- /solr (Configuration directory for solr)&lt;br /&gt;
&lt;br /&gt;
3. Click on &amp;quot;Check Solr instance Setting&amp;quot;. if it Shows ping successful(with an success image). Now click save changes.&lt;br /&gt;
&lt;br /&gt;
4. Now click on &amp;quot;Index courses&amp;quot; to index all the courses. After successful indexing. It will come up with a success image.&lt;br /&gt;
&lt;br /&gt;
5. Click on &amp;quot;Optimize&amp;quot; to optimize the existing indexes And improve solr performance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Enjoy the Search by going on page (http://127.0.0.1/MoodleInstallationURL/course/search.php)&lt;br /&gt;
&lt;br /&gt;
To configure navigation with the course search page goto Site administration -&amp;gt; Front page -&amp;gt; Front page settings.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Course search plugin snapshots:-&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* Course search admin tool&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Course_search_Adminui.png|700px|thumb|left]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;* Course search results&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
[[File:Course_Search_IntraWordQuery.png|700px|thumb|left]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;*Advance course search auto-suggestions&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
[[File:autocomplete.png|700px|thumb|left]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Schedule ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;May 28 - June 17 ( Community Bonding Period)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
➢ Discuss the further ideas with the mentor .&lt;br /&gt;
&lt;br /&gt;
➢ Final list of tasks to be implemented under this project.&lt;br /&gt;
&lt;br /&gt;
➢ Read &amp;amp; study the documentations on moodle and its Database Schema.&lt;br /&gt;
&lt;br /&gt;
➢ Study the plugin development in moodle.&lt;br /&gt;
&lt;br /&gt;
➢ Study the Apache Solr Documentation &amp;amp; its complete working&lt;br /&gt;
&lt;br /&gt;
➢ Set up the development and testing environment.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;June 18- july 10( Interim Period )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
➢ Start Coding!&lt;br /&gt;
&lt;br /&gt;
➢ Prepare moodle course search schema xml configuration&lt;br /&gt;
&lt;br /&gt;
➢ Create moodle plugins (admin tool and theme) that allow to substitute core search with alternative solution. At first it will duplicate the existing functionality but it is ready for modifications without changing the core.&lt;br /&gt;
&lt;br /&gt;
➢ Create function for manual reindexing of all courses, add button for admin on the plugin page to perform manual reindexing.&lt;br /&gt;
&lt;br /&gt;
➢ Implement the search in the plugin just to make sure it works with the simple result output (no filtering, no pagination, no additional information retrieval, etc)&lt;br /&gt;
&lt;br /&gt;
➢  Document the work.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;July 11- August  02( Interim Period )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
➢ Display courses properly, filtered, with all additional information&lt;br /&gt;
&lt;br /&gt;
➢ Add caching of search results so everything is not retrieved again when user requests the second page&lt;br /&gt;
&lt;br /&gt;
➢ Prepare search plugin for distrubution: create install/upgrade/uninstall scripts, write Readme file how to install and configure Solr.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mid Term Evaluation&lt;br /&gt;
&lt;br /&gt;
Submit code of completed tasks along with documentation.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;August 3- August 25 (Interim period)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
➢ Listen to events and mark courses for reindexing&lt;br /&gt;
&lt;br /&gt;
➢ Implement cron function that does reindexing&lt;br /&gt;
&lt;br /&gt;
➢ Add configurable settings to the plugin (when/whether to run automatic re indexing)&lt;br /&gt;
&lt;br /&gt;
➢ Document the work.&lt;br /&gt;
&lt;br /&gt;
➢ Debug the code and reduce code complexity.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;August 26- Sep 16 (Interim period)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
➢ Filtering results by dates, tags.&lt;br /&gt;
&lt;br /&gt;
➢ Spell correction capability.&lt;br /&gt;
&lt;br /&gt;
➢ Fuzzy search support.&lt;br /&gt;
&lt;br /&gt;
➢ Implement extra functionality (if any other feature required and time permits).&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;Sep 17- Sep 23(Pencils down)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
➢ Testing, documentation &amp;amp; debugging.&lt;br /&gt;
&lt;br /&gt;
➢ Final Release&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
Require moodle 2.5 and Apache solr 4.x&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mentors:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=1334243&amp;amp;course=5 Marina Glancy] &amp;amp; [https://moodle.org/user/profile.php?id=381842  Michael de Raadt]&lt;br /&gt;
&lt;br /&gt;
== Tracker ==&lt;br /&gt;
&lt;br /&gt;
*   CONTRIB-4335 Course Search Plugin&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC/2013|Moodle GSoC projects for 2013]]&lt;br /&gt;
* [[GSOC|Moodle GSoC Overview page]]&lt;br /&gt;
*  [http://www.google-melange.com/gsoc/proposal/review/google/gsoc2013/shashitechno/1 GSOC Proposal]&lt;br /&gt;
*  [https://docs.moodle.org/dev/Projects_for_new_developers#Course_search Original idea]&lt;br /&gt;
&lt;br /&gt;
[[Category:GSOC]]&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_reports&amp;diff=64553</id>
		<title>Course reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_reports&amp;diff=64553"/>
		<updated>2025-02-10T08:05:25Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
A course report plugin is just another folder inside course/report/. It follows standard plugin practice and may have lang, db etc. sub-folders if these are required. A version.php file must be included. &lt;br /&gt;
&lt;br /&gt;
In order to add a menu entry for your plugin, you must define a function named &#039;&#039;FOOBAR_report_extend_navigation&#039;&#039; in your &#039;&#039;lib.php&#039;&#039; file, where FOOBAR is your plugin name.&lt;br /&gt;
For example, for a module named &#039;&#039;synopsis&#039;&#039; (coursereport_synopsis in standardized form), the code will be :&lt;br /&gt;
&lt;br /&gt;
 function synopsis_report_extend_navigation($reportnav, $course, $context) {&lt;br /&gt;
     $url = new moodle_url(&#039;/course/report/synopsis/index.php&#039;, array(&#039;id&#039; =&amp;gt; $course-&amp;gt;id));&lt;br /&gt;
     $reportnav-&amp;gt;add(get_string(&#039;Synopsis&#039;, &#039;coursereport_synopsis&#039;), $url);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_formats_2&amp;diff=64552</id>
		<title>Course formats 2</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_formats_2&amp;diff=64552"/>
		<updated>2025-02-10T08:05:09Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Course formats refactoring&lt;br /&gt;
|state = FINAL DISCUSSION OF SPECIFICATION&lt;br /&gt;
|tracker = MDL-35218&lt;br /&gt;
|assignee = [[User:Marina Glancy|Marina Glancy]]&lt;br /&gt;
|discussion = http://moodle.org/mod/forum/discuss.php?d=212405&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.4}}&lt;br /&gt;
&lt;br /&gt;
We will refactor the course formats to support a proper object-oriented design and flexibility&lt;br /&gt;
==Database changes==&lt;br /&gt;
* change course.format from varchar(10) to varchar(21)&lt;br /&gt;
* add table course_format_options that will store format-specific options for the whole course and for specific secions (fields: id, courseid, format, sectionid[optional], name, value)&lt;br /&gt;
* remove existing fields in table course: numsections, hiddensections, coursedisplay&lt;br /&gt;
&lt;br /&gt;
==Object model==&lt;br /&gt;
&lt;br /&gt;
Course formats must be classes inheriting base &#039;&#039;&#039;class format_base&#039;&#039;&#039; instead of the current collection of callbacks. (Although some callbacks will be converted to methods)&lt;br /&gt;
&lt;br /&gt;
Method &#039;&#039;&#039;course_get_format($course)&#039;&#039;&#039; will return an instance of this class for the particular course. May be called with specific format but with empty course id (i.e. when course is being created)&lt;br /&gt;
&lt;br /&gt;
===Class format_base===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! method&lt;br /&gt;
! description&lt;br /&gt;
|-&lt;br /&gt;
| get_default_blocks()&lt;br /&gt;
| replaces config.php with $format[‘defaultblocks’]&lt;br /&gt;
|-&lt;br /&gt;
| course_format_options()&lt;br /&gt;
| definitions of the additional options that this course format uses for course&lt;br /&gt;
|-&lt;br /&gt;
| section_format_options()&lt;br /&gt;
| definitions of the additional options that this course format uses for section&lt;br /&gt;
|-&lt;br /&gt;
| edit_form_validation()&lt;br /&gt;
| performs additional validation for edit course form&lt;br /&gt;
|-&lt;br /&gt;
| page_set_course()&lt;br /&gt;
| is called from moodle_page::set_course() allowing course formats to run custom code at that point&lt;br /&gt;
|-&lt;br /&gt;
| page_set_cm()&lt;br /&gt;
| is called from moodle_page::set_cm()&lt;br /&gt;
|-&lt;br /&gt;
| output_course_header()&lt;br /&gt;
| displays the course-specific header. It will be included in all core themes, custom themes need to add support for it. Inside it should call function from renderer&lt;br /&gt;
|-&lt;br /&gt;
| output_course_footer()&lt;br /&gt;
| displays the course-specific footer&lt;br /&gt;
|-&lt;br /&gt;
| output_course_content_header()&lt;br /&gt;
| displays the course-specific header to be displayed in main content section (i.e. prev-next module navigation)&lt;br /&gt;
|-&lt;br /&gt;
| output_course_content_footer()&lt;br /&gt;
| displays the course-specific footer to be displayed in main content section (i.e. prev-next module navigation)&lt;br /&gt;
|-&lt;br /&gt;
| editsection_form()&lt;br /&gt;
| returns an instance of editsection_form (the format can overwrite this form)&lt;br /&gt;
|-&lt;br /&gt;
| is_section_current()&lt;br /&gt;
| replaces format_section_renderer_base::is_section_current()&lt;br /&gt;
|-&lt;br /&gt;
| get_section_name()&lt;br /&gt;
| is called from global function get_section_name()&lt;br /&gt;
|-&lt;br /&gt;
| uses_sections()&lt;br /&gt;
| is called from global function course_format_uses_sections()&lt;br /&gt;
|-&lt;br /&gt;
| supports_ajax()&lt;br /&gt;
| is called from global function course_format_ajax_support()&lt;br /&gt;
|-&lt;br /&gt;
| extend_course_navigation()&lt;br /&gt;
| replaces callback_FORMAT_load_content()&lt;br /&gt;
|-&lt;br /&gt;
| get_view_url()&lt;br /&gt;
| is called from course_get_url() and replaces callback_FORMAT_get_section_url()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Backward compartibility==&lt;br /&gt;
&lt;br /&gt;
Define class format_legacy extends format_base that will call the existing callbacks and get blocks from config.php if format class is not defined (2.0-2.3 backward compartibility). Function course_get_format() will return instance of this class if the course format does not define its own class&lt;br /&gt;
&lt;br /&gt;
==Course sections hierarchy==&lt;br /&gt;
&lt;br /&gt;
Add support for nested course sections: &lt;br /&gt;
* avoid loops,&lt;br /&gt;
* store visibleold;&lt;br /&gt;
* Process moving, deleting sections;&lt;br /&gt;
* Make sure the hierarchy appears in navigation menu and breadcrumb;&lt;br /&gt;
* Make sure changing of availability rules for both parent and child sections works correctly together&lt;br /&gt;
&lt;br /&gt;
Core formats will NOT support hierarchy, we just want to make sure that non-plugin code can deal with it&lt;br /&gt;
&lt;br /&gt;
==Course add/edit form==&lt;br /&gt;
&lt;br /&gt;
* When course is created/edited, the options specific for the format are displayed in separate form section and it dynamically changes when format is changed (with support of non-js mode). Each course format defines which display options it needs. For the standard weeks/topics formatd they are [numsections, hiddensections, coursedisplay], for scrom and social there are no options&lt;br /&gt;
* Make Course format selector on create/edit course page looking similar to &amp;quot;Add activity&amp;quot; with help text for each format&lt;br /&gt;
&lt;br /&gt;
==Course sections management==&lt;br /&gt;
&lt;br /&gt;
* ? Add events_triggers in functions that create/delete/hide/move course sections&lt;br /&gt;
* Refactor class editsection_form so it is easier to overwrite and implements functions set_data() and get_data() instead of pre/post processing data in editsection.php&lt;br /&gt;
&lt;br /&gt;
==Add course formats as plugin to site administration==&lt;br /&gt;
&lt;br /&gt;
Course formats are plugins in the code, but they are not handled as plugins in the administration. Replace course default settings by this page. Move page to plugins.&lt;br /&gt;
&lt;br /&gt;
* option to enable/disable a course format&lt;br /&gt;
* each course format may have it&#039;s own configurable options such as default and/or sticky blocks, default settings, etc.&lt;br /&gt;
&lt;br /&gt;
==Other changes related to course formats==&lt;br /&gt;
&lt;br /&gt;
* Make sure backup/restore correctly works with sections hierarchy and new options. Also backup made in previous versions restores correctly in 2.4&lt;br /&gt;
* Make sure course format can influence navigation menu and breadcrumb. This probably will be done already by set_course/set_cm callbacks&lt;br /&gt;
* Course formats may want to extend course settings navigation. Implement additional callback or do it in set_course() ?&lt;br /&gt;
* Improvement: file_info (Server files repository) should list modules inside the course groupped by sections&lt;br /&gt;
* Describe in course formats dev documentation how formats can watch the events triggers&lt;br /&gt;
&lt;br /&gt;
==Changes to course-related functions in 2.4==&lt;br /&gt;
(see MDL-35339)&lt;br /&gt;
* add function get_module_types_names() to replace $modnames and $modnamesplural in get_all_mods()&lt;br /&gt;
* add course_modinfo::get_used_module_types() to replace $modnamesused in get_all_mods()&lt;br /&gt;
* deprecate function get_all_mods(), change it&#039;s usage&lt;br /&gt;
* deprecate function get_all_sections()&lt;br /&gt;
* deprecate add_mod_to_section() and replace it with course_add_cm_to_section() to fix the mess in arguments&lt;br /&gt;
&lt;br /&gt;
==Comments to the changes of the specification==&lt;br /&gt;
&lt;br /&gt;
During actual development the specification was changed a little.&lt;br /&gt;
* table course_sections will not have additional fields &#039;parent&#039; and &#039;visibilityold&#039;. If course format wants to support hierarchy, they should be defined as additional format options. There will be no performance change if we add those fields to the course_sections table because the information about all sections is cached anyway in course.sectioncache and should be accessed only using get_fast_modinfo()&lt;br /&gt;
* there is no need in trigger &#039;course_format_changed&#039; because there is already a trigger &#039;course_updated&#039; and before it the format_base::update_course_format_options() is called with the before-update value of $course object&lt;br /&gt;
* field course.format has the length 21 because if format wants to define it&#039;s own tables the table name should start with &#039;format_FORMATNAME&#039; and at the same time it&#039;s name should not be longer than 28 symbols. Therefore there is 21 char left for FORMATNAME&lt;br /&gt;
* function format_base::is_setup_completed() is not necessary because this functionality can be done in page_set_course() hook.&lt;br /&gt;
&lt;br /&gt;
==Wishlist==&lt;br /&gt;
&lt;br /&gt;
* Add field course_module.sortorder and deprecate course_section.sequence (not in 2.4!)&lt;br /&gt;
&lt;br /&gt;
==Class course (for discussion, NOT for 2.4)==&lt;br /&gt;
There are number of course-related functions in the core with random names. The argument name/property &#039;section&#039; is used for both {section}.id and {section}.section, sometimes even the same variable changes it&#039;s meaning. Some very important functions completely miss phpdocs.&lt;br /&gt;
&lt;br /&gt;
Besides it will be more understandable for developers of modules and other plugins to relate to course object and not to course format (for example to get section name, etc.)&lt;br /&gt;
&lt;br /&gt;
The proposal is:&lt;br /&gt;
* move code of all those functions into new class &#039;course&#039;&lt;br /&gt;
* leave the functions themselves in course/deprecatedlib.php with developer warning and call to corresponding function from course class&lt;br /&gt;
* update usage of those functions in the core&lt;br /&gt;
* add function get_course() or course_get_course() to retrieve the cached instance of the course, make sure cache is emptied inside rebuid_course_cache()&lt;br /&gt;
* try to replace multiple similar queries $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039;=&amp;gt;$courseid)) in the core code&lt;br /&gt;
&lt;br /&gt;
Source of course/lib.php: https://github.com/moodle/moodle/blob/master/course/lib.php&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Existing function&lt;br /&gt;
! New function&lt;br /&gt;
|-&lt;br /&gt;
| get_fast_modinfo()&lt;br /&gt;
| ? course::get_modinfo()&lt;br /&gt;
|-&lt;br /&gt;
| get_array_of_activities()&lt;br /&gt;
| course::get_array_of_activities() [used only by get_fast_modinfo()]&lt;br /&gt;
|-&lt;br /&gt;
| course_set_marker()&lt;br /&gt;
| course::set_marker()&lt;br /&gt;
|-&lt;br /&gt;
| set_section_visible&lt;br /&gt;
| course::set_section_visible()&lt;br /&gt;
|-&lt;br /&gt;
| add_course_module()&lt;br /&gt;
| course::add_cm_raw() This function only creates an entry in table {course_module}&lt;br /&gt;
|-&lt;br /&gt;
| course_add_cm_to_section()&lt;br /&gt;
| course::cm_add_to_section()&lt;br /&gt;
|-&lt;br /&gt;
| -&lt;br /&gt;
| course::add_cm() calls previous two functions and rebuild_course_cache()&lt;br /&gt;
|-&lt;br /&gt;
| get_course_section()&lt;br /&gt;
| course::get_or_create_section() will return section_info&lt;br /&gt;
|-&lt;br /&gt;
| -&lt;br /&gt;
| course::get_section() will return section_info, alias to get_fast_modinfo()-&amp;gt;get_section_info()&lt;br /&gt;
|-&lt;br /&gt;
| -&lt;br /&gt;
| course::get_sections() alias to get_fast_modinfo()-&amp;gt;get_section_info_all()&lt;br /&gt;
|-&lt;br /&gt;
| set_coursemodule_groupmode()&lt;br /&gt;
| course::set_cm_groupmode()&lt;br /&gt;
|-&lt;br /&gt;
| set_coursemodule_idnumber()&lt;br /&gt;
| course::set_cm_idnumber()&lt;br /&gt;
|-&lt;br /&gt;
| set_coursemodule_visible()&lt;br /&gt;
| course::set_cm_visible()&lt;br /&gt;
|-&lt;br /&gt;
| delete_course_module()&lt;br /&gt;
| course::delete_cm_raw()&lt;br /&gt;
|-&lt;br /&gt;
| delete_mod_from_section()&lt;br /&gt;
| course::delete_cm_from_section()&lt;br /&gt;
|-&lt;br /&gt;
| -&lt;br /&gt;
| course::delete_cm() will call both previous functions&lt;br /&gt;
|-&lt;br /&gt;
| move_section_to()&lt;br /&gt;
| course::move_section(), also call rebuild_course_cache()&lt;br /&gt;
|-&lt;br /&gt;
| reorder_sections()&lt;br /&gt;
| course::reorder_sections(), also call rebuild_course_cache()&lt;br /&gt;
|-&lt;br /&gt;
| moveto_module()&lt;br /&gt;
| course::move_cm()&lt;br /&gt;
|-&lt;br /&gt;
| course_format_name()&lt;br /&gt;
| course::get_formatted_name()&lt;br /&gt;
|-&lt;br /&gt;
| get_section_name()&lt;br /&gt;
| format_base::get_section_name() with aliases: course::get_section_name() and section_info::get_name() &lt;br /&gt;
|-&lt;br /&gt;
| can_delete_course()&lt;br /&gt;
| course::can_delete()&lt;br /&gt;
|-&lt;br /&gt;
| create_course()&lt;br /&gt;
| course::create() [static]&lt;br /&gt;
|-&lt;br /&gt;
| update_course()&lt;br /&gt;
| course::update()&lt;br /&gt;
|-&lt;br /&gt;
| course_ajax_enabled()&lt;br /&gt;
| course::is_ajax_enabled()&lt;br /&gt;
|-&lt;br /&gt;
| include_course_ajax()&lt;br /&gt;
| course::include_ajax()&lt;br /&gt;
|-&lt;br /&gt;
| course_get_url()&lt;br /&gt;
| course::get_view_url()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other course-related functions in course/lib.php&lt;br /&gt;
&lt;br /&gt;
* get_print_section_cm_text()&lt;br /&gt;
* print_section()&lt;br /&gt;
* print_section_add_menus()&lt;br /&gt;
* get_module_metadata()&lt;br /&gt;
* print_course&lt;br /&gt;
* make_editing_buttons()&lt;br /&gt;
* course_allowed_module()&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_Tags&amp;diff=64551</id>
		<title>Course Tags</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_Tags&amp;diff=64551"/>
		<updated>2025-02-10T08:03:56Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Course tags&lt;br /&gt;
|state = Specification draft&lt;br /&gt;
|tracker = MDL-36648&lt;br /&gt;
|assignee = [[User:Andrew Nicols|Andrew Nicols]]&lt;br /&gt;
|discussion = &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
&lt;br /&gt;
The existing course tagging system in Moodle is quite restrictive and is preventing use of course tags in more complex use cases. It would&lt;br /&gt;
be ideal if course tags could be used to inform other areas of Moodle as to which courses may be of particular interest to a user.  As an&lt;br /&gt;
example, course tagging could be used to influence which courses are displayed in:&lt;br /&gt;
* block_course_overview - perhaps by use of course tag filters; and&lt;br /&gt;
* navigation - perhaps by using the same filters as in the block_course_overview or maybe looking at a users current context and showing them courses with similar tags to the course they are currently viewing.&lt;br /&gt;
&lt;br /&gt;
Course tags should not be tied directly to a context and they should be an admin-configurable system-wide setting.&lt;br /&gt;
&lt;br /&gt;
Course tags could also be linked closely with cohorts to allow restriction of /listing/ of courses based on cohorts. This is a widely requested feature in Moodle and would have a relatively small performance overhead.&lt;br /&gt;
&lt;br /&gt;
==User Stories==&lt;br /&gt;
&lt;br /&gt;
We have three users, Geoff, Jane, and Bob. They are all taking courses as Noodle University which has a number of Departments.&lt;br /&gt;
&lt;br /&gt;
* Noodle University has been using Moodle as its VLE for several years and allows students to have access to the courses they have taken in previous years.&lt;br /&gt;
* All students in Noodle University are automatically enrolled onto courses using the Database Enrolment mechanism which also manages their cohort membership based upon various factors including their faculty, department, and major choices.&lt;br /&gt;
* Noodle has several departments including Modern Languages, Maths, and Physics:&lt;br /&gt;
** The Modern Language department offers courses in French, Italian, German, and Spanish; as well as a beginners TEFL course;&lt;br /&gt;
** The Math department offers a variety of courses most of which are available to any math student, but with some only available to those studying a particular field.&lt;br /&gt;
** The Physics department offers a variety of courses and requires its students to choose at least one math course in their first year.&lt;br /&gt;
&lt;br /&gt;
The following tags have been set up at Noodle University (these are just a subset of them):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tag&lt;br /&gt;
! Description&lt;br /&gt;
! Requirements&lt;br /&gt;
|-&lt;br /&gt;
| currentyear&lt;br /&gt;
| Courses run in the academic year starting 2012&lt;br /&gt;
| None&lt;br /&gt;
|-&lt;br /&gt;
| year2011&lt;br /&gt;
| Courses run in the academic year starting 2011&lt;br /&gt;
| None&lt;br /&gt;
|-&lt;br /&gt;
| year2013&lt;br /&gt;
| Courses run in the academic year starting 2013&lt;br /&gt;
| None&lt;br /&gt;
|-&lt;br /&gt;
| languagemajor&lt;br /&gt;
| Courses in the language department which are taken by Language majors&lt;br /&gt;
| Membership of the &#039;languagemajor&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| languageminor&lt;br /&gt;
| Courses in the language department which are taken by Language minors&lt;br /&gt;
| Membership of the &#039;languageminor&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| language-french&lt;br /&gt;
| French courses in the Language department&lt;br /&gt;
| Membership of the &#039;language-french&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| language-german&lt;br /&gt;
| German courses in the Language department&lt;br /&gt;
| Membership of the &#039;language-german&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| language-spanish&lt;br /&gt;
| Spanish courses in the Language department&lt;br /&gt;
| Membership of the &#039;language-spanish&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| language-italian&lt;br /&gt;
| Italian courses in the Language department&lt;br /&gt;
| Membership of the &#039;language-italian&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| mathmajor&lt;br /&gt;
| Courses in the math department which are taken by math majors&lt;br /&gt;
| Membership of the &#039;mathmajor&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| mathminor&lt;br /&gt;
| Courses in the math department which are taken by math minor&lt;br /&gt;
| Membership of the &#039;mathminor&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| math-stats&lt;br /&gt;
| Statistics courses offered by the Math department&lt;br /&gt;
| Membership of the &#039;math-stats&#039; cohort&lt;br /&gt;
|-&lt;br /&gt;
| math-trig&lt;br /&gt;
| Trigonometry courses offered by the Math department&lt;br /&gt;
| Membership of the &#039;math-trig&#039; cohort&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Looking at some of Noodle&#039;s departments, staff have tagged all of the courses such that the courses have the following tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Year&lt;br /&gt;
! Course&lt;br /&gt;
! tags&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| FREN200&lt;br /&gt;
| language-french, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| FREN201&lt;br /&gt;
| language-french, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| FREN202&lt;br /&gt;
| language-french, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| GERM200&lt;br /&gt;
| language-german, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| GERM201&lt;br /&gt;
| language-german, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| GERM202&lt;br /&gt;
| language-german, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| ITAL200&lt;br /&gt;
| language-italian, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| ITAL201&lt;br /&gt;
| language-italian, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| ITAL202&lt;br /&gt;
| language-italian, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| SPAN201&lt;br /&gt;
| language-spanish, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| SPAN202&lt;br /&gt;
| language-spanish, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| SPAN203&lt;br /&gt;
| language-spanish, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH100&lt;br /&gt;
| math-major, math-minor, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH110&lt;br /&gt;
| math-major, math-minor, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH120&lt;br /&gt;
| math-major, math-minor, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH130&lt;br /&gt;
| math-major, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH140&lt;br /&gt;
| math-major, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH210&lt;br /&gt;
| math-stats, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2011-2012&lt;br /&gt;
| MATH220&lt;br /&gt;
| math-trig, year2011&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| FREN300&lt;br /&gt;
| language-french, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| FREN301&lt;br /&gt;
| language-french, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| FREN302&lt;br /&gt;
| language-french, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| GERM300&lt;br /&gt;
| language-german, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| GERM301&lt;br /&gt;
| language-german, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| GERM302&lt;br /&gt;
| language-german, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| ITAL300&lt;br /&gt;
| language-italian, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| ITAL301&lt;br /&gt;
| language-italian, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| ITAL302&lt;br /&gt;
| language-italian, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| SPAN301&lt;br /&gt;
| language-spanish, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| SPAN302&lt;br /&gt;
| language-spanish, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| SPAN303&lt;br /&gt;
| language-spanish, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| TEFL350&lt;br /&gt;
| language-major, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH100&lt;br /&gt;
| math-major, math-minor, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH110&lt;br /&gt;
| math-major, math-minor, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH120&lt;br /&gt;
| math-major, math-minor, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH130&lt;br /&gt;
| math-major, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH140&lt;br /&gt;
| math-major, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH210&lt;br /&gt;
| math-stats, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2012-2013&lt;br /&gt;
| MATH220&lt;br /&gt;
| math-trig, currentyear&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| FREN300&lt;br /&gt;
| language-french, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| FREN301&lt;br /&gt;
| language-french, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| FREN302&lt;br /&gt;
| language-french, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| GERM300&lt;br /&gt;
| language-german, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| GERM301&lt;br /&gt;
| language-german, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| GERM302&lt;br /&gt;
| language-german, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| ITAL300&lt;br /&gt;
| language-italian, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| ITAL301&lt;br /&gt;
| language-italian, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| ITAL302&lt;br /&gt;
| language-italian, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| SPAN301&lt;br /&gt;
| language-spanish, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| SPAN302&lt;br /&gt;
| language-spanish, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| SPAN303&lt;br /&gt;
| language-spanish, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| TEFL350&lt;br /&gt;
| language-major, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH100&lt;br /&gt;
| math-major, math-minor, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH110&lt;br /&gt;
| math-major, math-minor, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH120&lt;br /&gt;
| math-major, math-minor, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH130&lt;br /&gt;
| math-major, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH140&lt;br /&gt;
| math-major, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH210&lt;br /&gt;
| math-stats, year2013&lt;br /&gt;
|-&lt;br /&gt;
| 2013-2014&lt;br /&gt;
| MATH220&lt;br /&gt;
| math-trig, year2013&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Noodle University have enabled the /my course page and by default show several blocks including:&lt;br /&gt;
* block_course_overview     - the standard Course Overview block listing courses you are currently enrolled on&lt;br /&gt;
* block_course_available    - a custom block developed by Noodle listing all courses within a defined set of course categories&lt;br /&gt;
&lt;br /&gt;
===User Story 1 - Jane===&lt;br /&gt;
Jane is a second-year Language student majoring in French and Italian. She is currently preparing for her third year and wishes to find out&lt;br /&gt;
more about her courses for the year to come. She only wants to be presented with information on the courses which she can actually take part&lt;br /&gt;
in.&lt;br /&gt;
&lt;br /&gt;
Jane has been placed into appropriate cohorts for her study including:&lt;br /&gt;
* language-major&lt;br /&gt;
* language-french&lt;br /&gt;
* language-german&lt;br /&gt;
&lt;br /&gt;
* Jane opens her /my page and clicks the option on the block_course_available page to only show courses for the 2013-2014 academic year.&lt;br /&gt;
* She is only interested in courses which she is eligible to take and is presented with a list of French, and Italian courses. She is also offered the option to take the TEFL course as she is a language major.&lt;br /&gt;
* Jane is only able to view courses in which she is currently enrolled in, and those she is interested in:&lt;br /&gt;
** FREN300&lt;br /&gt;
** FREN301&lt;br /&gt;
** FREN302&lt;br /&gt;
** ITAL300&lt;br /&gt;
** ITAL301&lt;br /&gt;
** ITAL302&lt;br /&gt;
** TEFL350&lt;br /&gt;
&lt;br /&gt;
===User Story 2 - Geoff===&lt;br /&gt;
Geoff is a first year physics student and needs to look at his options for his second term. He has to choose from a selection of Math modules in addition to the compulsory Physics modules he has already been enrolled on.&lt;br /&gt;
&lt;br /&gt;
* Geoff opens his /my page and clicks the option on the block_course_available page to only show courses for the current academic year&lt;br /&gt;
* Geoff is presented with a list of modules that he is able to take:&lt;br /&gt;
** MATH100&lt;br /&gt;
** MATH110&lt;br /&gt;
** MATH120&lt;br /&gt;
&lt;br /&gt;
===User Story 3 - Bob===&lt;br /&gt;
&lt;br /&gt;
Bob is a third-year undergraduate Language student. He has taken 10-12 courses in each year of his degree and still has access to these courses for his studies.&lt;br /&gt;
He wants to be able to limit the courses shown on his Course Overview block to just the courses he is actively studying and hide the courses he is not.&lt;br /&gt;
He also wants the same courses to be shown on the &#039;My courses&#039; section of his Navigation tree.&lt;br /&gt;
&lt;br /&gt;
* Geoff opens Moodle and is directed to his /my page&lt;br /&gt;
* Geoff is presented with a list of modules that he is currently enrolled in and is taking this academic year:&lt;br /&gt;
** GERM301&lt;br /&gt;
** GERM302&lt;br /&gt;
** TEFL350&lt;br /&gt;
** SPAN301&lt;br /&gt;
** SPAN303&lt;br /&gt;
** /several more/&lt;br /&gt;
* Geoff wishes to view some of the courses he took last year, so he clicks from the drop-down list in the course overview block and selects pre-defined filter option for &#039;2011-2012 Academic year&#039;. The block updates to show:&lt;br /&gt;
** GERM204&lt;br /&gt;
** GERM205&lt;br /&gt;
** GERM206&lt;br /&gt;
** SPAN201&lt;br /&gt;
** /several more/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Database changes==&lt;br /&gt;
&lt;br /&gt;
New Tables:&lt;br /&gt;
&lt;br /&gt;
coursetag&lt;br /&gt;
* id&lt;br /&gt;
* idnumber&lt;br /&gt;
* name&lt;br /&gt;
* description&lt;br /&gt;
* descriptionformat&lt;br /&gt;
* timecreated&lt;br /&gt;
* timemodified&lt;br /&gt;
&lt;br /&gt;
coursetag_courses&lt;br /&gt;
* id&lt;br /&gt;
* coursetagid&lt;br /&gt;
* courseid&lt;br /&gt;
&lt;br /&gt;
coursetag_cohorts&lt;br /&gt;
* id&lt;br /&gt;
* coursetagid&lt;br /&gt;
* cohortid&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sample queries===&lt;br /&gt;
&lt;br /&gt;
Select all courses with any of tags a, b, or c and any of tags d, e, or f and that user matches any cohort membership requirements&lt;br /&gt;
  SELECT&lt;br /&gt;
    c.*&lt;br /&gt;
  FROM {course} c&lt;br /&gt;
  INNER JOIN {coursetag_courses} ctc ON ctc.courseid = c.id&lt;br /&gt;
  INNER JOIN {coursetags} ct ON ct.id = ctc.coursetagid&lt;br /&gt;
  LEFT JOIN {coursetag_cohorts} ctch ON ctch.coursetagid = ct.id&lt;br /&gt;
  LEFT JOIN {cohort_members} chm ON chm.id = ctch.cohortid&lt;br /&gt;
  WHERE chm.userid = ? AND (&lt;br /&gt;
    ct.id IN (a, b, c) AND&lt;br /&gt;
    ct.id IN (d, e, f)&lt;br /&gt;
  ) AND&lt;br /&gt;
  ( ctch.id IS NULL OR ch.id IS NOT NULL )&lt;br /&gt;
&lt;br /&gt;
==Object model==&lt;br /&gt;
&lt;br /&gt;
===Class course_tag===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! method&lt;br /&gt;
! type&lt;br /&gt;
! description&lt;br /&gt;
|-&lt;br /&gt;
| create()&lt;br /&gt;
| static&lt;br /&gt;
| creates a new course tag&lt;br /&gt;
|-&lt;br /&gt;
| remove()&lt;br /&gt;
| static&lt;br /&gt;
| removes a tag and all associations&lt;br /&gt;
|-&lt;br /&gt;
| fetch_by_name()&lt;br /&gt;
| &lt;br /&gt;
| Fetches a tag and it&#039;s details by its unique name&lt;br /&gt;
|-&lt;br /&gt;
| fetch_by_id()&lt;br /&gt;
| &lt;br /&gt;
| Fetches a tag and it&#039;s details by its unique id&lt;br /&gt;
|-&lt;br /&gt;
| add_to_course()&lt;br /&gt;
| &lt;br /&gt;
| Add a course to the current tag&lt;br /&gt;
|-&lt;br /&gt;
| remove_from_course()&lt;br /&gt;
|&lt;br /&gt;
| Remove the specified course from the current tag&lt;br /&gt;
|-&lt;br /&gt;
| fetch_courses()&lt;br /&gt;
|&lt;br /&gt;
| List all courses under the current tag&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Backwards compatibility==&lt;br /&gt;
None - we should get rid of the old interface if possible&lt;br /&gt;
&lt;br /&gt;
==User interface==&lt;br /&gt;
&lt;br /&gt;
==Future thoughts to consider==&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Core_plugins_review_for_Moodle_4.0&amp;diff=64550</id>
		<title>Core plugins review for Moodle 4.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Core_plugins_review_for_Moodle_4.0&amp;diff=64550"/>
		<updated>2025-02-10T08:03:37Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Core plugins review&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-72046 (epic)&lt;br /&gt;
|discussion = [https://moodle.org/mod/forum/discuss.php?d=426053 Moodle core plugins review]&lt;br /&gt;
|assignee = Sara Arjona&lt;br /&gt;
}}&lt;br /&gt;
{{Template:Moodle 4.0}}&lt;br /&gt;
==Introduction==&lt;br /&gt;
This project is about reviewing the plugins in core Moodle LMS with the aim of removing any which are no longer or hardly used, and if appropriate, adding them to the Moodle plugins directory.&lt;br /&gt;
==Plugins to be deleted from core==&lt;br /&gt;
The following plugins will be deleted from core but not put in the plugins directory because the technology is discontinued.&lt;br /&gt;
* WebCT question import/export format (qformat_webct)&lt;br /&gt;
* Examview question import/export format (qformat_examview)&lt;br /&gt;
* Flash animation media player (media_swf)&lt;br /&gt;
* VideoJS Flash plugin&lt;br /&gt;
* Picasa repository (repository_picasa)&lt;br /&gt;
* Picasa portfolio (portfolio_picasa)&lt;br /&gt;
* Microsoft OneDrive (legacy)	(repository_skydrive)&lt;br /&gt;
==Plugins to be removed from core and added to the plugins directory==&lt;br /&gt;
Plugins which have been removed from core and added to the plugins directory will initially be listed with Moodle HQ as maintainer while we seek new maintainers via the [[Plugins adoption programme]].&lt;br /&gt;
* Word censorship filter (filter_censor)&lt;br /&gt;
* Health center admin tool (tool_health)&lt;br /&gt;
* Jabber notification (message_jabber)&lt;br /&gt;
* Quiz results block (block_quiz_results)&lt;br /&gt;
* Box repository (repository_boxnet)&lt;br /&gt;
* Box portfolio (portfolio_boxnet)&lt;br /&gt;
Note the plugins can be added to the Plugins directory only once the target version 4.0 is registered there, which happens on beta release.&lt;br /&gt;
&lt;br /&gt;
==Plugins we are thinking about removing from core in the future and adding to the plugins directory==&lt;br /&gt;
We still need to decide which of the following plugins should be removed from core and added to the plugins directory. It will be done in MDL-73136 (epic). Please let us know your thoughts by posting in the discussion on moodle.org [https://moodle.org/mod/forum/discuss.php?d=426053 Moodle core plugins review]. We will collate all your feedback and review what to do with each plugin.&lt;br /&gt;
* Algebra notation filter (filter_algebra)&lt;br /&gt;
* Assignment 2.2 module (mod_assignment): MDL-72350&lt;br /&gt;
* Equella repository (repository_equella)&lt;br /&gt;
* Flickr block (block_tag_flickr): MDL-72614 &lt;br /&gt;
* Flickr portfolio (portfolio_flickr): MDL-72614  &lt;br /&gt;
* Flickr repository (repository_flickr): MDL-72614  &lt;br /&gt;
* Flickr public repository (repository_flickr_public): MDL-72614  &lt;br /&gt;
* HTML tidy filter (filter_tidy)&lt;br /&gt;
* Legacy course files repository (repository_coursefiles)&lt;br /&gt;
* Mahara ePortfolio (portfolio_mahara)&lt;br /&gt;
* Merlot.org repository (repository_merlot)&lt;br /&gt;
* Survey activity (mod_survey)&lt;br /&gt;
* URL downloader repository (repository_url)&lt;br /&gt;
== How will these plugins be removed from core? ==&lt;br /&gt;
* The plugin folder (for instance, question/format/webct/ for qformat_webct), will be completely removed from Moodle core. IMPORTANT: if you want to keep any of the plugins removed from core in your Moodle site, you will need to download and copy the plugin folder to the right place BEFORE running the upgrading process.&lt;br /&gt;
* Each plugin will be removed from the standard_plugins_list() method and added to the is_deleted_standard_plugin() method (both placed in lib/classes/plugin_manager.php).&lt;br /&gt;
[[File:jabber tobedeleted.png|center|thumb|The plugins will be marked as &amp;quot;To be deleted&amp;quot; if their code is not placed again in the Moodle folder.]]&lt;br /&gt;
* The upgrading steps will be added to lib/db/upgrade.php, to remove, when it applies, specific:&lt;br /&gt;
** DB tables (drop table statements).&lt;br /&gt;
** settings, using unset_all_config_for_plugin().&lt;br /&gt;
** capabilities, using capabilities_cleanup().&lt;br /&gt;
** ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugins data will be removed only if the plugins files are not present anymore in the code. So, if a site wants to keep any of the plugins removed from core, they should download and copy the plugin folder to the right place (as they use to do with third-party plugins) BEFORE running the upgrading process.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Community_hub_-_technical_specification&amp;diff=64549</id>
		<title>Community hub - technical specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Community_hub_-_technical_specification&amp;diff=64549"/>
		<updated>2025-02-10T08:01:55Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
= Implementation =&lt;br /&gt;
The community hub project is implemented in core (site related code), and as two external plugins.&lt;br /&gt;
== Moodle core ==&lt;br /&gt;
In Moodle core we added:&lt;br /&gt;
* a new registration form&lt;br /&gt;
* a community block (search course, import and restore course)&lt;br /&gt;
* some course publication operations&lt;br /&gt;
&lt;br /&gt;
== Hub server ==&lt;br /&gt;
A  hub server is a plugin in /local/hub/. Note that in Moodle core, there is a little hack that detect the plugin, and display a specific hub front page. &lt;br /&gt;
&lt;br /&gt;
The plugin can be found into Contrib CVS.&lt;br /&gt;
&lt;br /&gt;
== Hub directory ==&lt;br /&gt;
A hub directory is a plugin in /local/hubdirectory. &lt;br /&gt;
&lt;br /&gt;
The plugin is not released.&lt;br /&gt;
&lt;br /&gt;
= Hub directory = &lt;br /&gt;
== Data structure==&lt;br /&gt;
on the hub directory we have a table named hub_directory containg all registered hubs :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int&lt;br /&gt;
|Standard autoincrement&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the hub&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|text&lt;br /&gt;
|Description of the hub&lt;br /&gt;
|-&lt;br /&gt;
|url&lt;br /&gt;
|varchar&lt;br /&gt;
|The full URL to the hub front page&lt;br /&gt;
|-&lt;br /&gt;
|token&lt;br /&gt;
|varchar&lt;br /&gt;
|The token used to call the hub&lt;br /&gt;
|-&lt;br /&gt;
|trusted&lt;br /&gt;
|int&lt;br /&gt;
|Is the hub trusted? &lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|varchar&lt;br /&gt;
|What is the primary language of this hub?  (blank for multilanguage)&lt;br /&gt;
|-&lt;br /&gt;
|timeregistered&lt;br /&gt;
|int&lt;br /&gt;
|Time that the hub was first registered&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int&lt;br /&gt;
|Time that the hub was last modified&lt;br /&gt;
|-&lt;br /&gt;
|contactname&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the contact person&lt;br /&gt;
|-&lt;br /&gt;
|contactemail&lt;br /&gt;
|varchar&lt;br /&gt;
|Email of the contact person&lt;br /&gt;
|-&lt;br /&gt;
|imageurl&lt;br /&gt;
|varchar&lt;br /&gt;
|hub logo url&lt;br /&gt;
|-&lt;br /&gt;
|visible&lt;br /&gt;
|int&lt;br /&gt;
|is hub visible (i.e. enable field)&lt;br /&gt;
|-&lt;br /&gt;
|prioritise&lt;br /&gt;
|int&lt;br /&gt;
|is this hub prioritised&lt;br /&gt;
|-&lt;br /&gt;
|courses&lt;br /&gt;
|int&lt;br /&gt;
|Number of courses on this hub &lt;br /&gt;
|-&lt;br /&gt;
|sites&lt;br /&gt;
|int&lt;br /&gt;
|Number of sites on this site &lt;br /&gt;
|-&lt;br /&gt;
|privacy&lt;br /&gt;
|varchar&lt;br /&gt;
|&amp;quot;public&amp;quot;/&amp;quot;private&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
on the hub directory we have a table named hub_global_course_directory containg all public published courses into all public hub:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int&lt;br /&gt;
|Standard autoincrement&lt;br /&gt;
|-&lt;br /&gt;
|hubid&lt;br /&gt;
|int&lt;br /&gt;
|Hub ID from the table hub_directory&lt;br /&gt;
|-&lt;br /&gt;
|sitename&lt;br /&gt;
|varchar&lt;br /&gt;
|Site name - can be blank&lt;br /&gt;
|-&lt;br /&gt;
|siteurl&lt;br /&gt;
|varchar&lt;br /&gt;
|Site URL- can be blank&lt;br /&gt;
|-&lt;br /&gt;
|fullname&lt;br /&gt;
|varchar&lt;br /&gt;
|Fullname of the course&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|text&lt;br /&gt;
|Description of the course&lt;br /&gt;
|-&lt;br /&gt;
|courseurl&lt;br /&gt;
|varchar&lt;br /&gt;
|The full URL to the course&lt;br /&gt;
|-&lt;br /&gt;
|contributornames&lt;br /&gt;
|varchar&lt;br /&gt;
|Contributor names&lt;br /&gt;
|-&lt;br /&gt;
|coverage&lt;br /&gt;
|varchar&lt;br /&gt;
|Coverage&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|varchar&lt;br /&gt;
|What is the language of this hub? &lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int&lt;br /&gt;
|Time that the course was last published&lt;br /&gt;
|-&lt;br /&gt;
|creatorname&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the creator&lt;br /&gt;
|-&lt;br /&gt;
|publishername&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the publisher&lt;br /&gt;
|-&lt;br /&gt;
|format&lt;br /&gt;
|varchar&lt;br /&gt;
|url or Zip&lt;br /&gt;
|-&lt;br /&gt;
|shortname&lt;br /&gt;
|varchar&lt;br /&gt;
|course short name&lt;br /&gt;
|-&lt;br /&gt;
|licenseshortname&lt;br /&gt;
|varchar&lt;br /&gt;
|license shortname&lt;br /&gt;
|-&lt;br /&gt;
|subject&lt;br /&gt;
|varchar&lt;br /&gt;
|subject&lt;br /&gt;
|-&lt;br /&gt;
|audience&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|educationallevel&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|coursemapid&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|creatornotes&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|creatornotesformat&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|privacy&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|downloadurl&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|originaldownloadurl&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|demourl&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|trusted&lt;br /&gt;
|int&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrollable&lt;br /&gt;
|int&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|screenshotsids&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrolcost&lt;br /&gt;
|int&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrolcostcurrency&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|downloadcost&lt;br /&gt;
|int&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|downloadcostcurrency&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== communication with hub ==&lt;br /&gt;
Communications between hub and hub directory are two ways, they can call each other by web service. For any hub/hub directory communication, we record the remote entity (i.e. hub directory/hub) in a table named hub_communication or hub_directory_communication. This is mainly used to remember the token used by the remote entity and the name of the remote entity. It&#039;s also used as a flag to know if a registration attempt has been confirmed.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int&lt;br /&gt;
|Standard autoincrement&lt;br /&gt;
|-&lt;br /&gt;
|localtype&lt;br /&gt;
|varchar&lt;br /&gt;
|Is our Moodle site a: Site, Hub or Hub directory&lt;br /&gt;
|-&lt;br /&gt;
|token&lt;br /&gt;
|text&lt;br /&gt;
|the token used for this communication&lt;br /&gt;
|-&lt;br /&gt;
|localws&lt;br /&gt;
|varchar&lt;br /&gt;
|What kind of entity is our site in this communication. Are we server or client?&lt;br /&gt;
|-&lt;br /&gt;
|remotetype&lt;br /&gt;
|varchar&lt;br /&gt;
|Is the remote Moodle site a: Site, Hub or Hub directory&lt;br /&gt;
|-&lt;br /&gt;
|remotename&lt;br /&gt;
|varchar&lt;br /&gt;
|Full name of the remote site&lt;br /&gt;
|-&lt;br /&gt;
|remoteurl&lt;br /&gt;
|varchar&lt;br /&gt;
|URL of the remote entity&lt;br /&gt;
|-&lt;br /&gt;
|confirmed&lt;br /&gt;
|int&lt;br /&gt;
|Is this confirmation confirmed (in case the registration/update failed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== registration process ===&lt;br /&gt;
# the hub admin goes on hub settings page =&amp;gt; settings are saved with set_config&lt;br /&gt;
# the hub admin presses register and is redirected to the hub directory registration page. This redirection has the token used by the hub directory. &lt;br /&gt;
# the hub admin enters a recaptcha on the hub directory registration page. It is mandatory to avoid people to write script automatically registering.&lt;br /&gt;
# the hub directory redirect the hub admin to his own site on a confirmation page. The redirection has the token used by the hub.&lt;br /&gt;
=== update process ===&lt;br /&gt;
# the hub admin changes the settings.&lt;br /&gt;
# the hub admin presses update registration.&lt;br /&gt;
# the hub calls by web service the update info function on the hub directory.&lt;br /&gt;
&lt;br /&gt;
== security design ==&lt;br /&gt;
* because there is a recaptcha, only human being can register.&lt;br /&gt;
* all other communications are protected by Moodle ws security design&lt;br /&gt;
* In order to use web service we automatically create Users/Services/Roles/Functions. All created users, web services functions, web services and web service tokens are visible in the admin user interface. Hub admin should not to delete them, neither create some with the same names. Hub admin can only modify the roles in order to restrict the capabilities to use some of the functions. To know about automatically created Users/Services/Roles, see their respective sections in this same page.&lt;br /&gt;
&lt;br /&gt;
= Hub server =&lt;br /&gt;
== Data structure==&lt;br /&gt;
Primarily this hub_site_directory table will store information about the sites that have registered course information on that Hub.  On hub.moodle.org this information will also be used for [http://moodle.org/stats general statistics] and the listing of [http://moodle.org/sites registered sites]:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int&lt;br /&gt;
|Standard autoincrement&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the site&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|text&lt;br /&gt;
|Description of the site&lt;br /&gt;
|-&lt;br /&gt;
|url&lt;br /&gt;
|varchar&lt;br /&gt;
|The full URL to the site front page&lt;br /&gt;
|-&lt;br /&gt;
|secret&lt;br /&gt;
|varchar&lt;br /&gt;
|The site secret used to confirm the registration and to not register a site twice.&lt;br /&gt;
|-&lt;br /&gt;
|trusted&lt;br /&gt;
|int&lt;br /&gt;
|Is the site trusted? &lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|varchar&lt;br /&gt;
|What is the primary language of this site?  (blank for multilanguage)&lt;br /&gt;
|-&lt;br /&gt;
|timeregistered&lt;br /&gt;
|int&lt;br /&gt;
|Time that the site was first registered&lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int&lt;br /&gt;
|Time that the site was last modified&lt;br /&gt;
|-&lt;br /&gt;
|contactname&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the contact person&lt;br /&gt;
|-&lt;br /&gt;
|contactemail&lt;br /&gt;
|varchar&lt;br /&gt;
|Email of the contact person&lt;br /&gt;
|-&lt;br /&gt;
|contactphone&lt;br /&gt;
|varchar&lt;br /&gt;
|Phone of the contact person&lt;br /&gt;
|-&lt;br /&gt;
|contactable&lt;br /&gt;
|int&lt;br /&gt;
|can we contact the person&lt;br /&gt;
|-&lt;br /&gt;
|imageurl&lt;br /&gt;
|varchar&lt;br /&gt;
|site logo url&lt;br /&gt;
|-&lt;br /&gt;
|visible&lt;br /&gt;
|int&lt;br /&gt;
|is site visible (i.e. enable field)&lt;br /&gt;
|-&lt;br /&gt;
|prioritise&lt;br /&gt;
|int&lt;br /&gt;
|is this site prioritised&lt;br /&gt;
|-&lt;br /&gt;
|countrycode&lt;br /&gt;
|varchar&lt;br /&gt;
|country code ISO 3166  (AU, FR etc) [http://cvs.moodle.org/moodle/lang/en_utf8/countries.php?view=markup lang/XX_utf8/countries.php]&lt;br /&gt;
|-&lt;br /&gt;
|regioncode&lt;br /&gt;
|varchar&lt;br /&gt;
|region code ISO 3166-2  [http://www.commondatahub.com/live/geography/state_province_region/iso_3166_2_state_codes ISO 3166-2 (XX-XXX)] (alphanumeric codes)&#039;&#039;&#039; (TODO: MDL-24020)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|street&lt;br /&gt;
|varchar&lt;br /&gt;
|street&lt;br /&gt;
|-&lt;br /&gt;
|geolocation&lt;br /&gt;
|varchar&lt;br /&gt;
|lattitude and longitute (like in googlemap/twitter)&lt;br /&gt;
|-&lt;br /&gt;
|moodleversion&lt;br /&gt;
|varchar&lt;br /&gt;
|Moodle version&lt;br /&gt;
|-&lt;br /&gt;
|moodlerelease&lt;br /&gt;
|varchar&lt;br /&gt;
|Moodle releasel&lt;br /&gt;
|-&lt;br /&gt;
|ip&lt;br /&gt;
|varchar&lt;br /&gt;
|last IP of this site&lt;br /&gt;
|-&lt;br /&gt;
|courses&lt;br /&gt;
|int&lt;br /&gt;
|Number of courses on this site &lt;br /&gt;
|-&lt;br /&gt;
|users&lt;br /&gt;
|int&lt;br /&gt;
|Number of users on this site &lt;br /&gt;
|-&lt;br /&gt;
|enrolments&lt;br /&gt;
|int&lt;br /&gt;
|Number of enrolments on this site &lt;br /&gt;
|-&lt;br /&gt;
|resources&lt;br /&gt;
|int&lt;br /&gt;
|Number of resources on this site &lt;br /&gt;
|-&lt;br /&gt;
|questions&lt;br /&gt;
|int&lt;br /&gt;
|Number of questions on this site &lt;br /&gt;
|-&lt;br /&gt;
|modulenumberaverage&lt;br /&gt;
|int&lt;br /&gt;
|Module number average on this site &lt;br /&gt;
|-&lt;br /&gt;
|participantnumberaverage&lt;br /&gt;
|int&lt;br /&gt;
|Participant number average on this site &lt;br /&gt;
|-&lt;br /&gt;
|emailalert&lt;br /&gt;
|int&lt;br /&gt;
|Do we send email notification - Subscribed to securityalerts@lists.moodle.org&lt;br /&gt;
|-&lt;br /&gt;
|privacy&lt;br /&gt;
|varchar&lt;br /&gt;
|&amp;quot;public&amp;quot;/&amp;quot;private&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|posts&lt;br /&gt;
|int&lt;br /&gt;
|Number of posts on this site &lt;br /&gt;
|-&lt;br /&gt;
|timevalidationfailed&lt;br /&gt;
|int&lt;br /&gt;
|The time the last time the site was not reach&lt;br /&gt;
|-&lt;br /&gt;
|deleted&lt;br /&gt;
|int&lt;br /&gt;
|is the site deleted&lt;br /&gt;
|-&lt;br /&gt;
|publicationmax&lt;br /&gt;
|int&lt;br /&gt;
|how many publication are allowed on the hub every day&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
On the hub server, the hub_course_directory table stores registered courses, one record per course.  Some courses will be &amp;quot;downloadable&amp;quot;, some will be enrollable, so different fields can be used. Note that from these data you can build the exact Dublin Core Metadata Element Set, Version 1.1:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int&lt;br /&gt;
|Standard autoincrement&lt;br /&gt;
|-&lt;br /&gt;
|siteid&lt;br /&gt;
|int&lt;br /&gt;
|Site ID from the table hub_site_directory&lt;br /&gt;
|-&lt;br /&gt;
|fullname&lt;br /&gt;
|varchar&lt;br /&gt;
|Fullname of the course&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|text&lt;br /&gt;
|Description of the course&lt;br /&gt;
|-&lt;br /&gt;
|courseurl&lt;br /&gt;
|varchar&lt;br /&gt;
|The full URL to the course&lt;br /&gt;
|-&lt;br /&gt;
|contributornames&lt;br /&gt;
|varchar&lt;br /&gt;
|Contributor names&lt;br /&gt;
|-&lt;br /&gt;
|coverage&lt;br /&gt;
|varchar&lt;br /&gt;
|Coverage&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|varchar&lt;br /&gt;
|What is the language of this hub? &lt;br /&gt;
|-&lt;br /&gt;
|timemodified&lt;br /&gt;
|int&lt;br /&gt;
|Time that the course was last published&lt;br /&gt;
|-&lt;br /&gt;
|creatorname&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the creator&lt;br /&gt;
|-&lt;br /&gt;
|publishername&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the publisher&lt;br /&gt;
|-&lt;br /&gt;
|format&lt;br /&gt;
|varchar&lt;br /&gt;
|url or Zip&lt;br /&gt;
|-&lt;br /&gt;
|shortname&lt;br /&gt;
|varchar&lt;br /&gt;
|course short name&lt;br /&gt;
|-&lt;br /&gt;
|licenseshortname&lt;br /&gt;
|varchar&lt;br /&gt;
|license shortname&lt;br /&gt;
|-&lt;br /&gt;
|subject&lt;br /&gt;
|varchar&lt;br /&gt;
|subject&lt;br /&gt;
|-&lt;br /&gt;
|audience&lt;br /&gt;
|varchar&lt;br /&gt;
|Audience:  Educators | Students | Admin&lt;br /&gt;
|-&lt;br /&gt;
|educationallevel&lt;br /&gt;
|varchar&lt;br /&gt;
|Educational level being discussed (for educators audience only):  Tertiary | Secondary | Primary | Government | Corporate | Association | Other&lt;br /&gt;
|-&lt;br /&gt;
|coursemapid&lt;br /&gt;
|varchar&lt;br /&gt;
|Is a course map supplied?   (Simple XML description of course structure, could be rendered graphically later [http://kn.open.ac.uk/public/workspace.cfm?wpid=8690 CompendiumLD] )&lt;br /&gt;
|-&lt;br /&gt;
|creatornotes&lt;br /&gt;
|varchar&lt;br /&gt;
|Creator notes (describes how to use the course, where it came from, context, more description etc)&lt;br /&gt;
|-&lt;br /&gt;
|creatornotesformat&lt;br /&gt;
|varchar&lt;br /&gt;
|Creator notes format (HTML etc)&lt;br /&gt;
|-&lt;br /&gt;
|privacy&lt;br /&gt;
|varchar&lt;br /&gt;
|Availability (public/private)&lt;br /&gt;
|-&lt;br /&gt;
|downloadurl&lt;br /&gt;
|varchar&lt;br /&gt;
|Download URL (usually a local cached zip but could be anything else, including empty for non-downloadable)&lt;br /&gt;
|-&lt;br /&gt;
|originaldownloadurl&lt;br /&gt;
|varchar&lt;br /&gt;
|Original Download URL (usually a download script on the original Moodle site, used by Hub to get cache)&lt;br /&gt;
|-&lt;br /&gt;
|demourl&lt;br /&gt;
|varchar&lt;br /&gt;
|Demo URL (a URL, if any, where the course can be seen in action)&lt;br /&gt;
|-&lt;br /&gt;
|trusted&lt;br /&gt;
|int&lt;br /&gt;
|Is the course trusted?  (all downloadable courses from non-trusted sites start as &amp;quot;no&amp;quot;, then this gets changed by someone who checks it)&lt;br /&gt;
|-&lt;br /&gt;
|enrollable&lt;br /&gt;
|int&lt;br /&gt;
|Is the course enrollable anyone with an account?&lt;br /&gt;
|-&lt;br /&gt;
|screenshots&lt;br /&gt;
|varchar&lt;br /&gt;
|Number of supplied screenshots&lt;br /&gt;
|-&lt;br /&gt;
|enrolcost&lt;br /&gt;
|int&lt;br /&gt;
|Enrol Cost (and currency) [http://en.wikipedia.org/wiki/ISO_4217 ISO 4217]&lt;br /&gt;
|-&lt;br /&gt;
|enrolcostcurrency&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|downloadcost&lt;br /&gt;
|int&lt;br /&gt;
|Download Cost (and currency) [http://en.wikipedia.org/wiki/ISO_4217 ISO 4217]&lt;br /&gt;
|-&lt;br /&gt;
|downloadcostcurrency&lt;br /&gt;
|varchar&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Dublin Core Metadata Element Set, Version 1.1&lt;br /&gt;
*# Contributor - course manager names or whoever the publisher nominates&lt;br /&gt;
*# Coverage - User tags&lt;br /&gt;
*# Creator - main teacher name or copyright holder or whoever the publisher nominates&lt;br /&gt;
*# Date - date this was last published/updated&lt;br /&gt;
*# Description - course description&lt;br /&gt;
*# Format - zip / url&lt;br /&gt;
*# Identifier - course shortname (unique on the original site)&lt;br /&gt;
*# Language - based on lang.php&lt;br /&gt;
*# Publisher - the name of the person who caused this record to be entered here&lt;br /&gt;
*# Relation - the site id that it came from&lt;br /&gt;
*# Rights - one of a standard set of open source, creative commons and other licenses&lt;br /&gt;
*# Source - original URL of the course&lt;br /&gt;
*# Subject - The best-matching item from ([[Standard Classification of Educational Fields]])&lt;br /&gt;
*# Title - Course fullname&lt;br /&gt;
*# Type - &amp;quot;course&amp;quot; (later there might other types such as activities or SCORM packages etc)&lt;br /&gt;
&lt;br /&gt;
TODO:&lt;br /&gt;
*# Is guest access allowed?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Course feedback ====&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* course id&lt;br /&gt;
* type (bug / comment)&lt;br /&gt;
* text &lt;br /&gt;
* rating (probably a rating ID =&amp;gt; futur rating API)&lt;br /&gt;
&lt;br /&gt;
TODO: a simple way to alert the publisher of new feedback on a course.&lt;br /&gt;
&lt;br /&gt;
==== Course content ====&lt;br /&gt;
&lt;br /&gt;
* id &lt;br /&gt;
* course id &lt;br /&gt;
* module type (activity / block)&lt;br /&gt;
* module name (forum, resource etc)&lt;br /&gt;
* count&lt;br /&gt;
&lt;br /&gt;
==== Course outcomes ====&lt;br /&gt;
&lt;br /&gt;
* id&lt;br /&gt;
* course id &lt;br /&gt;
* outcome  (text)&lt;br /&gt;
&lt;br /&gt;
== communication between site and hub ==&lt;br /&gt;
The site registration process is similar to &amp;quot;Hub registration on hub directory&amp;quot;, except that the site doesn&#039;t create any ws token for the hub. However the site creates a secret key in order to confirm the registration process, the hub sending it back at the end of the process. The communication between site and hub are one way only, site to hub.&lt;br /&gt;
&lt;br /&gt;
= Registered site =&lt;br /&gt;
== tables==&lt;br /&gt;
On the registered sites we have a table named hub_course_published containg all published courses.&lt;br /&gt;
&lt;br /&gt;
== communication ==&lt;br /&gt;
Sites send files calling a upload.php script on the hub.&lt;br /&gt;
&lt;br /&gt;
= List of communications between the three entities =&lt;br /&gt;
Following the different communication operations expected between Moodle.org, hub servers and Moodle site.&lt;br /&gt;
&lt;br /&gt;
== Moodle site and Hub server==&lt;br /&gt;
One way communications, site to hub.&lt;br /&gt;
&lt;br /&gt;
== Moodle.org Hub directory and (Moodle.org) Hub server ==&lt;br /&gt;
[[Image:Hubdirectory_moodleorg2hubserver_moodle.org.png|900x950px]]&lt;br /&gt;
&lt;br /&gt;
== Moodle site and Moodle.org Hub directory ==&lt;br /&gt;
[[Image:Moodlesite2moodleorg.png|900x950px]]&lt;br /&gt;
&lt;br /&gt;
= How does the communication work =&lt;br /&gt;
We are going to use Moodle web services. We will create a new /hub/webservice.php entry point It will bypass $CFG-&amp;gt;enablewebservice and it will consider a choosen protocol as activated.  &lt;br /&gt;
&lt;br /&gt;
== Registration operations ==&lt;br /&gt;
#The hub creates a specific ws user, a specific ws role, a specific ws service and a specific token. &lt;br /&gt;
#The hub sends by POST the web service token to the site/hub directory.&lt;br /&gt;
&lt;br /&gt;
== Unknown caller operations ==&lt;br /&gt;
the webservice.php entry point should by pass token authentication for some public functions.&lt;br /&gt;
=== public function list ===&lt;br /&gt;
* global search&lt;br /&gt;
* search courses on a hub&lt;br /&gt;
* get hub list from the hub directory&lt;br /&gt;
&lt;br /&gt;
= Required roles for community hub web services =&lt;br /&gt;
&lt;br /&gt;
==Moodle.org Hub list ==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Public Directory User&amp;quot; - Role for any sites :&lt;br /&gt;
*moodle/hubs:view (public token for any sites) for searching the global listing&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Directory User&amp;quot; - Role for hub to update the listing:&lt;br /&gt;
*moodle/hubs:updateinfo (private token for any registered hub) for updating hub information (it creates a new private token different from the one used to call this function)&lt;br /&gt;
&lt;br /&gt;
==Hub server==&lt;br /&gt;
&lt;br /&gt;
Will have one new user per registered site, plus one for Moodle.org hub directory and one for pubic users.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Public Hub User&amp;quot; - Role for any site (public token)&lt;br /&gt;
*moodle/hub:view for course searches&lt;br /&gt;
*moodle/hub:rate for rating a course&lt;br /&gt;
*moodle/hub:comment for commenting a course&lt;br /&gt;
*moodle/hub:download for downloading a course template&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Registered Hub User&amp;quot; -  Role for registered sites (private token -&amp;gt; each site gets a private user)&lt;br /&gt;
*moodle/hub:view for course searches&lt;br /&gt;
*moodle/hub:rate for rating a course&lt;br /&gt;
*moodle/hub:comment for commenting a course&lt;br /&gt;
*moodle/hub:download for downloading a course template&lt;br /&gt;
*moodle/hub:publish for publishing a course template&lt;br /&gt;
*moodle/hub:updateinfo (private token for any registered site) for updating site information (it creates a new private token different from the one used to call this function)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Moodle.org Hub Directory&amp;quot;  -  Role for Moodle.org Hub Directory (private token)&lt;br /&gt;
*moodle/hub:viewinfo for getting hub information&lt;br /&gt;
*moodle/hub:view for getting course information&lt;br /&gt;
*moodle/hub:confirmhubregistration confirm the registration&lt;br /&gt;
&lt;br /&gt;
= Required community hub web services =&lt;br /&gt;
We will have one hidden service per role. Following their name:&lt;br /&gt;
&lt;br /&gt;
==Moodle.org Hub list ==&lt;br /&gt;
the following service will exist only on Moodle.org Hub directory&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Hub directory public site&amp;quot;:&lt;br /&gt;
*global search function&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Hub directory hub server&amp;quot;:&lt;br /&gt;
*update info function&lt;br /&gt;
&lt;br /&gt;
==Hub server==&lt;br /&gt;
the following services will exist on any Moodle site (but disabled till a first token is linked to it)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Public site&amp;quot;:&lt;br /&gt;
* course searches function&lt;br /&gt;
* rating a course function&lt;br /&gt;
* commenting a course function&lt;br /&gt;
* downloading a course template function&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Registered site&amp;quot; &lt;br /&gt;
*course searches function&lt;br /&gt;
*rating a course function&lt;br /&gt;
*commenting a course function&lt;br /&gt;
*downloading a course template function&lt;br /&gt;
*publishing a course template function&lt;br /&gt;
*update info function&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Hub directory&amp;quot;&lt;br /&gt;
*getting hub information function&lt;br /&gt;
*getting course information function&lt;br /&gt;
*confirm the hub registration function&lt;br /&gt;
&lt;br /&gt;
= Required users for community hub web services =&lt;br /&gt;
&lt;br /&gt;
==Moodle.org Hub list ==&lt;br /&gt;
A user is be linked to one role only and one service only&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Public sites&amp;quot;: they all use the same &#039;&#039;public_directory_user&#039;&#039; user.&lt;br /&gt;
*His role is &#039;Public Directory User&#039;&lt;br /&gt;
*His service is &#039;Hub directory public site&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Hub servers&amp;quot;: they all have their own $huburl.&amp;quot;_directory_hub_user&amp;quot; user.&lt;br /&gt;
*Their role is &#039;Directory user&#039;&lt;br /&gt;
*Their service is &#039;Hub directory hub server&#039;&lt;br /&gt;
&lt;br /&gt;
==Hub server==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Public sites&amp;quot;: they all use the same &#039;public_hub_user&#039; user.&lt;br /&gt;
*His role is &#039;Public Hub User&#039;&lt;br /&gt;
*His service is &#039;Public site&#039; &lt;br /&gt;
&lt;br /&gt;
&amp;quot;Registered sites&amp;quot;: they all have their own $siteurl.&#039;_registered_site_user&#039; user.&lt;br /&gt;
*Their role is &#039;Registered Hub User&#039;.&lt;br /&gt;
*Their service is &#039;Registered site&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Hub directory&amp;quot;: they use their own $hubdirectoryurl.&#039;_directory_user&#039; (in case the hub directory change his url)&lt;br /&gt;
*Their role is &#039;Moodle.org Hub Directory&#039;.&lt;br /&gt;
*Their service is &#039;Hub directory&#039;.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [https://docs.moodle.org/en/Community_hub Community hub]&lt;br /&gt;
* [https://docs.moodle.org/en/Development:Community_hub Development: community hub project specification]&lt;br /&gt;
&lt;br /&gt;
[[Category:Hub]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=64548</id>
		<title>Community hub</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Community_hub&amp;diff=64548"/>
		<updated>2025-02-10T08:01:20Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PROJECT STATE: implemented&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;MAIN TRACKER ISSUE&#039;&#039;&#039;: MDL-19309&lt;br /&gt;
* &#039;&#039;&#039;DISCUSSION AND COMMENTS&#039;&#039;&#039;: [http://moodle.org/mod/forum/view.php?id=7330 Hub servers] forum in Using Moodle&lt;br /&gt;
* &#039;&#039;&#039;MAIN AUTHORS&#039;&#039;&#039;: [[User:Martin_Dougiamas|Martin Dougiamas]] and [[User:jerome_mouneyrac|Jerome Mouneyrac]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This page describes an overall functional specification for the &amp;quot;Moodle Community Hub&amp;quot; project, which consists of a new system (the Moodle Hub Server) and several new features in Moodle 2.0. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Goals and rationale =&lt;br /&gt;
&lt;br /&gt;
The main goals of the Community hub project are:&lt;br /&gt;
&lt;br /&gt;
# to allow people to easily find courses around the world that they want to enrol in:&lt;br /&gt;
#* educators want to find &#039;&#039;&#039;communities of practice&#039;&#039;&#039; that are subject or region-oriented, so that they can associate with their peers on a long-term basis.&lt;br /&gt;
#* other learners want to find and study courses on various other subjects&lt;br /&gt;
# to make it easy for educators to find and download &#039;&#039;&#039;course templates&#039;&#039;&#039; from other people.  This will help educators share and identify examples of &#039;&#039;&#039;best practice&#039;&#039;&#039; in online pedagogy and hopefully improve the average quality of online courses.&lt;br /&gt;
&lt;br /&gt;
Finally, we want to do all this in the simplest, safest way possible, while allowing a range of scenarios such as courses that are public or private, free or paid, so that the Moodle community can build solutions for themselves.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Overview =&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the basic idea.  The systems in this diagram are:&lt;br /&gt;
&lt;br /&gt;
;Ordinary Moodle site: A typical Moodle site with teachers who want to download course templates and/or users who want to connect (enrol) with external communities &lt;br /&gt;
;Publishing site: A Moodle site that wants to make some of its courses available for download&lt;br /&gt;
;Community site: A Moodle site that provides courses that are enrollable&lt;br /&gt;
;Moodle Hub Server: A new Moodle plugin for listing registered courses that are &#039;&#039;&#039;downloadable&#039;&#039;&#039; or &#039;&#039;&#039;enrollable&#039;&#039;&#039;.  The default hub will be installed at hub.moodle.org, but there can be many others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Community-hubs-flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
Downloadable courses&lt;br /&gt;
* (A) Sites that want to publish certain courses and make them downloadable can register them with one or more Hub Servers.&lt;br /&gt;
* (B) The Hub will check the data and make sure the course zip is downloadable, caching a copy locally.  The Hub may also have a security process to check the download for trojan horses, bad content, etc.&lt;br /&gt;
* (C) The download process may trigger the backup process on the original server if it hasn&#039;t been done already.&lt;br /&gt;
* (D) Later, Moodle users (who have permissions to do so) can connect to a Hub to search for downloadable courses and choose one.&lt;br /&gt;
* (E) The Moodle site downloads the file and makes it available to the Moodle user so they can now continue to restore it normally.&lt;br /&gt;
&lt;br /&gt;
Enrollable courses&lt;br /&gt;
* (1) Sites that want to publish certain courses for the public to enrol in can register them with one or more hub (including the main one at moodle.org)&lt;br /&gt;
* (2) Later, any Moodle user can connect to a hub (via Community block in their site) to search and find courses they want to join&lt;br /&gt;
* (3) They click on a link to be sent to the other site so that they can enrol there.&lt;br /&gt;
&lt;br /&gt;
= Use Cases =&lt;br /&gt;
&lt;br /&gt;
== New teacher creating a course ==&lt;br /&gt;
&lt;br /&gt;
# New teacher needs some help with a new course for &amp;quot;Alligator farming 101&amp;quot;&lt;br /&gt;
# Teacher sees the &amp;quot;Community&amp;quot; block into the &amp;quot;Alligator farming 101&amp;quot; course page and presses &amp;quot;Search course&amp;quot;&lt;br /&gt;
# Teacher browses a list of downloadable courses in the community page (the data comes from one or more Hubs via web services)&lt;br /&gt;
# Teacher searches for &amp;quot;Alligator&amp;quot; &lt;br /&gt;
# Teacher finds 4 courses that look good, and after reading reviews and ratings, chooses one.&lt;br /&gt;
# The course is downloaded and unpacked in Moodle.&lt;br /&gt;
# The teacher now has a good starter course they can keep developing.&lt;br /&gt;
&lt;br /&gt;
== New teacher needs help ==&lt;br /&gt;
&lt;br /&gt;
A teacher decides they need some help and wants to talk with others teaching Alligator farming.&lt;br /&gt;
&lt;br /&gt;
# Teacher goes to their &amp;quot;Community&amp;quot; block and clicks &amp;quot;Search course&amp;quot;.&lt;br /&gt;
# Moodle displays a page to search for courses (the data comes from one or more Hubs via web services)&lt;br /&gt;
# Teacher searches courses for &amp;quot;educator&amp;quot; courses on &amp;quot;Alligators&amp;quot; in their country/language.&lt;br /&gt;
# Teacher finds two, selects one, and is returned to the page where is was before clicking on &amp;quot;Search course&amp;quot;.  The selected course is now permanently listed in the Community block.&lt;br /&gt;
# Teacher clicks on the link and is taken to the course, where they can enrol and interact/learn with peers over time, subscribe to forums etc.&lt;br /&gt;
&lt;br /&gt;
== University consortium ==&lt;br /&gt;
&lt;br /&gt;
A group of five universites wants to share courses among themselves and not to the outside world.  They also want to prevent teachers from downloading courses from outside the consortium.&lt;br /&gt;
&lt;br /&gt;
# Someone downloads Moodle and installs it as a private Moodle Hub Server&lt;br /&gt;
# Admins of all five Moodle sites in the group add the URL of the private Hub to their settings and register their sites there&lt;br /&gt;
# The default Hub at hub.moodle.org is (optionally) disabled in the site-wide settings.&lt;br /&gt;
# Admins register their courses with the Hub.&lt;br /&gt;
# Teachers can now import, export or join courses via the private Hub.&lt;br /&gt;
&lt;br /&gt;
== Course creation business ==&lt;br /&gt;
NOT IMPLEMENTED&lt;br /&gt;
&lt;br /&gt;
CoolCourses Inc have produced a set of 50 good Moodle courses which they wish to sell.&lt;br /&gt;
&lt;br /&gt;
# They set up a Moodle site with all their courses in them.&lt;br /&gt;
# They set up a Hub with a payment system, and register it with the Hub List at moodle.org so people can find it&lt;br /&gt;
# They register all their courses with their own Hub with appropriate metadata&lt;br /&gt;
# When looking for courses, users can either &lt;br /&gt;
#* find this Hub by browsing through the Hub List, or &lt;br /&gt;
#* type the URL of the Hub directly into their Moodle site&lt;br /&gt;
# When users try to download a course, they may see a payment button to download it (credit card, paypal etc)&lt;br /&gt;
# CoolCourses could provide limited access to the courses on their Moodle site using Roles, as a preview.&lt;br /&gt;
&lt;br /&gt;
= Components =&lt;br /&gt;
&lt;br /&gt;
There are several components:&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;Hub List&#039;&#039;&#039;: A list of known Hub Servers, kept on moodle.org &lt;br /&gt;
;&#039;&#039;&#039;Hub Server&#039;&#039;&#039;: A new Moodle plugin for publishing a list of registered courses that are &#039;&#039;&#039;downloadable&#039;&#039;&#039; or &#039;&#039;&#039;enrollable&#039;&#039;&#039;&lt;br /&gt;
;&#039;&#039;&#039;Course registration&#039;&#039;&#039;: A new mechanism in every Moodle to register particular courses with one or more Hub Servers&lt;br /&gt;
;&#039;&#039;&#039;Community membership block&#039;&#039;&#039;: to search Hub Servers to find enrollable courses to join and bookmark&lt;br /&gt;
;&#039;&#039;&#039;Import/Export block&#039;&#039;&#039;: Makes it easy to find downloadable course templates in a Hub Server, then download them from the Hub Server and restore them locally&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Moodle Hub List==&lt;br /&gt;
The Hub List is a list of known Hub Servers (see the next section).  This makes it easy for Moodle users to find the most appropriate Hub Servers for their needs.  To get on the Hub List, Hub Servers choose to register with moodle.org via their administration interface.&lt;br /&gt;
&lt;br /&gt;
Moodle.org will store the following information, and make it available via a browseable interface at [http://hubdirectory.moodle.org/ hhttp://hubdirectory.moodle.org/].&lt;br /&gt;
&lt;br /&gt;
==Moodle Hub Server==&lt;br /&gt;
[[Image:Registerhub.png| thumb |Mockup: hub registration page]]&lt;br /&gt;
The Moodle Hub Server (aka Hub) is a separate system (based on Moodle technology) that allows Moodle sites to register their courses for listing there. More technically, the hub server is a Moodle plugin.&lt;br /&gt;
&lt;br /&gt;
A default installation of this software will be running at &#039;&#039;&#039;hub.moodle.org&#039;&#039;&#039;, but anyone else can download it and set up their own hub for private or public uses.   A hub can also be used as a Moodle site, even though the Moodle front page will be replaced by the hub front page.&lt;br /&gt;
&lt;br /&gt;
Hubs can optionally register themselves in the Hub List so that they are easier to find and so they can become a &amp;quot;Trusted Hub&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A hub server has some config fields (saved into its database):&lt;br /&gt;
* name (site name by default, changing the value here, do not change the site name)&lt;br /&gt;
* description (front page summary as default value)&lt;br /&gt;
* language (choose the language, set site language as default)&lt;br /&gt;
* contact name (current user by default)&lt;br /&gt;
* contact email&lt;br /&gt;
* enable&lt;br /&gt;
* password (only for private hub)&lt;br /&gt;
* logo url (need to have a limited size of 150x150)&lt;br /&gt;
* protected web search interface &#039;&#039;&#039;(TODO: MDL-24015)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Data structure ===&lt;br /&gt;
Most of the data structure can be found in the [https://docs.moodle.org/en/Development:Community_hub_-_technical_specification community hub technical specification].&lt;br /&gt;
&lt;br /&gt;
=== User interface ===&lt;br /&gt;
[[Image:Webinterface.png|thumb|Mockup: search course UI]]&lt;br /&gt;
If visiting the hub via the web, it will provide an interface for full searching and browsing.  &lt;br /&gt;
&lt;br /&gt;
The web interface can be protected from access.  The hub at moodle.org will of course be open to all.&lt;br /&gt;
&lt;br /&gt;
[[Image:Search_hub_moodle.png|thumb|Mockup: search hub UI]]&lt;br /&gt;
&lt;br /&gt;
The web interface allows users to:&lt;br /&gt;
&lt;br /&gt;
* search by keyword (descriptions, titles, tags, subject etc)&lt;br /&gt;
* browse a list of courses by subject&lt;br /&gt;
* go directly to a course (if marked for public use)&lt;br /&gt;
* preview a course (if screenshots have been provided, or the original URL location)&lt;br /&gt;
* download the course to desktop (only if an download url has been set)&lt;br /&gt;
* If logged in to the Hub, users can also:&lt;br /&gt;
** give a rating to the course&lt;br /&gt;
** write a comment for the course - &amp;lt;span style=color:blue&amp;gt;use comment 2.0 API&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When displaying courses, you can see and sort by:&lt;br /&gt;
&lt;br /&gt;
* Title - &#039;&#039;Sortable&#039;&#039;&lt;br /&gt;
* Description&lt;br /&gt;
* Tags  - &#039;&#039;Sortable &amp;lt;span style=color:blue&amp;gt;(first tag retrieved by the request is considered)&amp;lt;/span&amp;gt;&#039;&#039;&lt;br /&gt;
* Screenshot(s)&lt;br /&gt;
* Cost (if any) - &#039;&#039;Sortable&#039;&#039;&lt;br /&gt;
* Rating (10-point scale displayed as 5 stars, and only if you are logged in to moodle.org) - &#039;&#039;Sortable&#039;&#039;&lt;br /&gt;
* Comments &lt;br /&gt;
* Moodle site name&lt;br /&gt;
* Date added to directory&lt;br /&gt;
* Date last updated in directory&lt;br /&gt;
* Audience (teachers, students, admins)&lt;br /&gt;
* Teacher name(s) - &#039;&#039;Sortable&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Web service interface ===&lt;br /&gt;
&#039;&#039;&#039;TODO: MDL-24031&#039;&#039;&#039;&lt;br /&gt;
A REST-based web services interface will be provided for other systems (eg Moodle sites) to use directly.&lt;br /&gt;
&lt;br /&gt;
Web services can search on:&lt;br /&gt;
* string search&lt;br /&gt;
* array language&lt;br /&gt;
* array cost&lt;br /&gt;
* array Moodle url&lt;br /&gt;
* Others?&lt;br /&gt;
&lt;br /&gt;
=== Hub admin interface ===&lt;br /&gt;
&lt;br /&gt;
The hub will have a Hub admin interface.  Admin processes include:&lt;br /&gt;
&lt;br /&gt;
* Listing, approving and editing the sites registered with the hub &lt;br /&gt;
* Listing, approving and editing the course descriptions, metadata etc.&lt;br /&gt;
* Registering/updating the Hub with the Hub List&lt;br /&gt;
* Configuring Hub behaviour and the appearance of the home page.&lt;br /&gt;
&lt;br /&gt;
== Course global search functionality ==&lt;br /&gt;
In order to quickly search a course on all public hubs, Moodle.org will have a table equivalent to the course &#039;directory&#039; table with dew additional field as &amp;quot;public hub id&amp;quot;, &amp;quot;site url&amp;quot;, &amp;quot;site name&amp;quot;...&lt;br /&gt;
&lt;br /&gt;
== Site registration ==&lt;br /&gt;
[[Image:SiteRegistration.png|thumb|Mockup: site registration UI]]&lt;br /&gt;
The existing site registration form in Moodle will be extended so that admins can:&lt;br /&gt;
&lt;br /&gt;
# choose one or more Hubs to register with (hub.moodle.org and/or others in the Hub List, or directly to a particular Hub specified by URL)&lt;br /&gt;
# choose to enable cron to re-send statistics to the hub on a periodic basis. (TODO/TBD)&lt;br /&gt;
# choose to enable the hub to harvest courses on a periodic basis (TODO: not shown on image/TBD)&lt;br /&gt;
&lt;br /&gt;
== Community membership ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Community&amp;quot; block allows people to find and subscribe to external courses that they want to be part of.&lt;br /&gt;
&lt;br /&gt;
Visibility of the block and the features within it are controlled by roles, and contains:&lt;br /&gt;
&lt;br /&gt;
# &#039;Bookmarks&#039; of previously-selected (subscribed) external courses (to make revisiting easy) grouped by site, which can be edited/deleted etc&lt;br /&gt;
# A link to a search script - &amp;quot;Add new courses...&amp;quot;&lt;br /&gt;
# A search script to browse/search one or more Hubs (via web services to get the data, with the interface rendered by the local script).  Users can select joinable courses from the list and they&#039;ll get added to the list in the block.&lt;br /&gt;
&lt;br /&gt;
Generally the links will be just be an ordinary URL and the remote site will be responsible for authentication.&lt;br /&gt;
&lt;br /&gt;
If the foreign site has an Mnet connection set up with the current site then login will be immediate.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Addacourse.png|thumb|Mockup: community block]]&lt;br /&gt;
&lt;br /&gt;
community block database structure:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name&lt;br /&gt;
! Type&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|int&lt;br /&gt;
|Standard autoincrement&lt;br /&gt;
|-&lt;br /&gt;
|userid&lt;br /&gt;
|int&lt;br /&gt;
|foreign key - ID of the user&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|coursename&lt;br /&gt;
|varchar&lt;br /&gt;
|Name of the community course&lt;br /&gt;
|-&lt;br /&gt;
|coursedescription&lt;br /&gt;
|text&lt;br /&gt;
|Description of the community course - display by the tag link&lt;br /&gt;
|-&lt;br /&gt;
|courseurl&lt;br /&gt;
|varchar&lt;br /&gt;
|The full URL to the community course front page&lt;br /&gt;
|-&lt;br /&gt;
|image&lt;br /&gt;
|varchar&lt;br /&gt;
|community course logo url - it could be displayed as icon&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Publish courses ==&lt;br /&gt;
 &#039;&#039;&#039;Publish course&#039;&#039;&#039;: to publish or update the description of the current course in one or more Hubs&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Publish&#039;&#039;&#039; button only exists if the current user has the appropriate capabilities and if the current Moodle site has been registered with a Hub.&lt;br /&gt;
&lt;br /&gt;
[[Image:Coursepublishing.png|thumb|Mockup: course publishing]]&lt;br /&gt;
&lt;br /&gt;
Choosing &amp;quot;Publish&amp;quot; goes to a script where you can chose from the registered Hubs and whether you want to publish the course as:&lt;br /&gt;
* enrollable/advertise, so that others can come here and use the course where it is, and/or &lt;br /&gt;
* downloadable/share, so that a Hub can offer this course for download to others&lt;br /&gt;
&lt;br /&gt;
If the user wants to offer this course for download, then they are directed to the standard backup process to create and define the backup file (without users!).  If the backup is successful the zip is stored in a standard place and then the user is returned to the publish script to continue.  (If downloads are not required then this whole step is skipped).&lt;br /&gt;
&lt;br /&gt;
It allows the user to set up full , and especially whether you want to advertise this course as being:&lt;br /&gt;
&lt;br /&gt;
Now the script presents a form with metadata that this course will be published with on the chosen Hub(s) (this is also available in the course settings page).  Metadata includes information such as description, licensing, categories, screenshots etc (see the [[#Courses|Courses]] section above for more info).&lt;br /&gt;
&lt;br /&gt;
After checking/updating the metadata, the script will push the data to the selected Hub. &lt;br /&gt;
&lt;br /&gt;
If the checkbox to allow download was selected, then the URL to a course upload script in the current Moodle is included with the metadata.  This URL contains a token (eg an MD5 stored in the course table) that only the Hub knows.&lt;br /&gt;
&lt;br /&gt;
The course upload script (eg /local/hub/webservice/upload.php?id=55&amp;amp;token=XXXXX) will expect the cached .zip file for the given course.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Publish course settings ====&lt;br /&gt;
&lt;br /&gt;
Some publish settings and info will also be available anytime via the course settings page under a &amp;quot;Publish&amp;quot; tab:&lt;br /&gt;
&lt;br /&gt;
* Which hubs has this course been published on, and when&lt;br /&gt;
* Full metadata&lt;br /&gt;
* Screenshots&lt;br /&gt;
&lt;br /&gt;
== Harvest courses ==&lt;br /&gt;
&#039;&#039;&#039;NOT IMPLEMENTED&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;Note: site to hub communication is one way only, the following text may change.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Each hub will use cron to call every site that has registered a harvesting url on a periodic basis.  This will be done at the same time as the link is checked to ensure the site is reachable, so the &amp;quot;time link was last checked&amp;quot; field in the site table also indicates when the site was last harvested.&lt;br /&gt;
&lt;br /&gt;
The harvesting url will be an RSS feed which will list all the courses to be included in the hub and their metadata.  This might be the feed of all visible courses on the site, or courses in a given category.  TODO: should we allow them to enter multiple category feeds so they can say &amp;quot;arts&amp;quot;, &amp;quot;business&amp;quot; and &amp;quot;languages&amp;quot; but not &amp;quot;science&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
Course list RSS feeds are an existing tracker item for Moodle 2.0  See http://tracker.moodle.org/browse/MDL-13248  This patch allows admins to pick which categories have individual feeds created and are included in the &amp;quot;all courses&amp;quot; feed.  Each course becomes an &amp;lt;item&amp;gt; in the RSS feed as follows:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;category&amp;gt; the Moodle course category in which the course belongs&lt;br /&gt;
* &amp;lt;title&amp;gt; the course fullname&lt;br /&gt;
* &amp;lt;link&amp;gt; the course url&lt;br /&gt;
* &amp;lt;pubdate&amp;gt; the date the course (or any of its resources and activities) last updated&lt;br /&gt;
* &amp;lt;description&amp;gt; the course summary&lt;br /&gt;
&lt;br /&gt;
The current tracker item will need to be extended to include appropriate course metadata in the RSS feed.  There is a [http://purl.org/dc/elements/1.1/ Dublin Core extension to RSS 2.0] which can be implemented.  &lt;br /&gt;
&lt;br /&gt;
TODO: If we choose an alternative metadata format we will need to locate or create an alternative RSS extension.  There is a [http://www.downes.ca/xml/RSS_LOM.htm LOM extension] but not from an official IEEE namespace.  &lt;br /&gt;
&lt;br /&gt;
We will need to declare our own namespace RSS extension to identify whether a course should be listed in the hub as downloadable and/or enrollable.  This extension will add tags to the RSS feed as follows:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;moodlehub:downloadable&amp;gt; &lt;br /&gt;
* &amp;lt;moodlehub:enrollable&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both tags will take either &amp;quot;yes&amp;quot; or &amp;quot;no&amp;quot; values and will be set by course creators at the same time as they enter course metadata.&lt;br /&gt;
&lt;br /&gt;
The hub will check the published date for each item in the RSS feed to identify whether it needs to update its records.  TODO: if we use OAI-PMH for harvesting we can request courses updated since x see http://moodle.org/mod/forum/discuss.php?d=127488 &lt;br /&gt;
&lt;br /&gt;
If the course has been updated and is &amp;lt;moodlehub:downloadable&amp;gt; is yes, then the hub will request the site to create a new backup of the entire course (less user data).&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [https://docs.moodle.org/en/Community_hub Community hub]&lt;br /&gt;
* [https://docs.moodle.org/en/Development:Community_hub_-_technical_specification Development: community hub technical specification]&lt;br /&gt;
&lt;br /&gt;
[[Category:Hub]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:コミュニティハブ]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Comments_UI_Update&amp;diff=64547</id>
		<title>Comments UI Update</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Comments_UI_Update&amp;diff=64547"/>
		<updated>2025-02-10T08:00:20Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
=== Scenarios ===&lt;br /&gt;
&lt;br /&gt;
==== Teacher Posts a Text Comment on Assignment Submission ====&lt;br /&gt;
&lt;br /&gt;
The teacher creates a text comment about the user’s assignment submission. The comment is posted and then a message is sent informing the student that a new comment for the assignment has been created by the teacher.&lt;br /&gt;
&lt;br /&gt;
==== Student Attaches File to a Comment on a Blog ====&lt;br /&gt;
&lt;br /&gt;
A Carl Monk wants to show Xao Xin Mei a mathematical article article with a proof that confirms the theory she proposed in her latest blog post on music and math. After creating the text of the post Carl would like to drag the article file to the comment and have it attached for Xao to download later.&lt;br /&gt;
&lt;br /&gt;
==== Student Posts Video Comment on an Assignment Submission ====&lt;br /&gt;
&lt;br /&gt;
Kristen Sanchez doesn’t agree with the grade that Alex Souza gave her on her english paper. She wants to make sure the Alex sees her frustration with the lack of comments on her face and wishes to post a video comment to the assignment. After setting up her web cam Kristen clicks on the web cam button and begins to record her video message to her Alex. After she stops the recording and saves the comment the video is displayed in the commenting area.&lt;br /&gt;
&lt;br /&gt;
==== Teacher Posts and Audio Comment to a Student’s Assignment ====&lt;br /&gt;
&lt;br /&gt;
Phill O’Neil prefers not to have to type out his comments to students, instead he like to save a running commentary as he reviews their assignment. Phill opens up the assignment and then starts and audio comment in the comments area of the assignment. As Phill reads he states areas of the document that need to change. After he has finished reviewing the assignment submission he saves the audio comment and the student can review it.&lt;br /&gt;
&lt;br /&gt;
==== Student Receives an Email That a new Comment has Been Posted ====&lt;br /&gt;
&lt;br /&gt;
Phill O’Niel has posted a comment on a math proof that Carl Monk submitted to his course. Carl has configured his message output to send an email to him whenever a new comment is created for an assignment. Carl receives an email stating that Phill has created a comment on his math submission and that he can view the comment by clicking on a link.&lt;br /&gt;
&lt;br /&gt;
=== Feature Information ===&lt;br /&gt;
&lt;br /&gt;
==== Commenting Configuration ====&lt;br /&gt;
&lt;br /&gt;
===== Description =====&lt;br /&gt;
&lt;br /&gt;
Not all sites will want to allow file attachments in their comments. Site administrators will be able to enable or disable the robust commenting features.&lt;br /&gt;
&lt;br /&gt;
===== Requirements =====&lt;br /&gt;
&lt;br /&gt;
# A new link will be added to the Settings block under the Site administration group called Comments. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# The comments link will display the comments settings page when clicked. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# A new checkbox setting for comments will be added called Allow file attachments. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# The allow file attachments checkbox will be checked by default. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# The allow file attachments checkbox will have the descriptive text of &#039;&#039;Allow user’s to upload files to comments.&#039;&#039; below the checkbox. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# A new drop down setting for comments will be added called maximum file upload. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# The maximum file upload drop down will have a default value of 2MB. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# The maximum file upload drop down will have the descriptive text of &#039;&#039;Define the largest size of file that can be uploaded to a comment, limited by the site-wide setting.&#039;&#039;. below the drop down. See [[#Comments_Settings|Mockup: Comments Settings]]&lt;br /&gt;
# The maximum file upload drop down will use the Moodle default upload size values with a maximum of the site upload limit setting.&lt;br /&gt;
# The the allow file attachments setting is unchecked then the maximum upload size setting will be disabled.&lt;br /&gt;
&lt;br /&gt;
===== Mockups =====&lt;br /&gt;
&lt;br /&gt;
====== Settings Comments Link ======&lt;br /&gt;
&lt;br /&gt;
[[Image:settingsCommentsLink.png|settingsCommentsLink.png]]&lt;br /&gt;
&lt;br /&gt;
====== Comments Settings ======&lt;br /&gt;
&lt;br /&gt;
[[Image:commentSettings.png|commentSettings.png]]&lt;br /&gt;
&lt;br /&gt;
===== Use Cases =====&lt;br /&gt;
&lt;br /&gt;
====== Site Administrator Disables File Attachments to Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The site administrator determines that files should not be attached to comments and disables the feature at the site level&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is configured to be a site administrator&lt;br /&gt;
# The user is at the site level&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The site administrator expands the Site administration group in the settings block&lt;br /&gt;
# The site administrator clicks on the comments link&lt;br /&gt;
# The site administrator unchecked the Allow file uploads checkbox&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Save changes&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The file attachments area of comments doesn’t display&lt;br /&gt;
# users can’t upload files to a comment&lt;br /&gt;
&lt;br /&gt;
====== Site Administrator Lowers the Maximum Upload Size in Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The site administrator determines that the maximum size of a file uploaded to a comment should be lower than the site maximum upload size.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is configured to be a site administrator&lt;br /&gt;
# The user is at the site level&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The site administrator expands the Site administration group in the settings block&lt;br /&gt;
# The site administrator clicks on the comments link&lt;br /&gt;
# The site administrator selects 100 KB for the Maximum upload size drop down&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Save changes&#039;&#039; button &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# When a user drags a file larger than 100 KB to the file area of a comment and error appears stating the file is too large.&lt;br /&gt;
&lt;br /&gt;
==== Commenting Updates ====&lt;br /&gt;
&lt;br /&gt;
===== Description =====&lt;br /&gt;
&lt;br /&gt;
Moodlerooms will update the commenting API to add file upload support and anonymous display of comments.&lt;br /&gt;
&lt;br /&gt;
===== Requirements =====&lt;br /&gt;
&lt;br /&gt;
# The Moodle comment API will support a minified file uploader if Allow file uploads is checked in the comments site settings. (See [[#Viewing_and_Adding_Comments|Mockup: Viewing and Adding Comments]])&lt;br /&gt;
# The mini file uploader will display the following information: (See [[#Viewing_and_Adding_Comments|Mockup: Viewing and Adding Comments]])&lt;br /&gt;
## Add file with icon&lt;br /&gt;
## Drag and drop area if supported by the browser&lt;br /&gt;
## A list of files with their file type icon under the add file and drag and drop area.&lt;br /&gt;
# A new file manager form type will be created to support the mini file uploader.&lt;br /&gt;
# Comments will not require text in the text area to be saved if a file is uploaded.&lt;br /&gt;
# The user will click the save comment button to record the comment in the comment display area. (See [[#Viewing_and_Adding_Comments|Mockup: Viewing and Adding Comments]])&lt;br /&gt;
# The comment display will be updated to display the following information about the comment:&lt;br /&gt;
## The user’s profile picture&lt;br /&gt;
## The user’s fist and last name&lt;br /&gt;
## The date and time the comment was posted.&lt;br /&gt;
# The comment display area will display comments based on the plugins display preferences. (See [[#Viewing_and_Adding_Comments|Mockup: Viewing and Adding Comments]]) for an example.&lt;br /&gt;
# The comment API will allow a developer to determine the order comments are displayed in. The options will be:&lt;br /&gt;
## Newest first&lt;br /&gt;
## Oldest first&lt;br /&gt;
# The comment API will allow the developer to load all comments or a range of comments.&lt;br /&gt;
# A comment with a file attached to it will display the file below the comment text. (See [[#File_Attachment_to_Comment|Mockup: File Attachment to Comment]])&lt;br /&gt;
# If the comment site settings allow file attachments setting is unchecked then any previously attached files will not display in the comments.&lt;br /&gt;
# When the user clicks the save comment button the comment and any attachments will immediately display in the comment display area.&lt;br /&gt;
# When a user deletes or saves a comment the comments api will return any new comments to be displayed to the user.&lt;br /&gt;
# The comments API will support a plugin requesting to renderer comments with anonymised user data &lt;br /&gt;
# When a comment is set to render with anonymised user data then the work Participant with a number will display instead of the user&#039;s name. See [Mockup: Anonymous Comment!#AnonymousComment]. &lt;br /&gt;
# When a comment is set to render with anonymised the number displayed with the participant text will be the user&#039;s id, context id for the comment and the item id all added together. See [Mockup: Anonymous Comment!#AnonymousComment]. &lt;br /&gt;
# When a comment is set to render with anonymised the user&#039;s identification will change based on the context and plugin that the user&#039;s is commenting on. See [Mockup: Anonymous Comment!#AnonymousComment]. &lt;br /&gt;
# The picture displayed with an anonymised comment will be the default user avatar for the Moodle theme. See [Mockup: Anonymous Comment!#AnonymousComment]. &lt;br /&gt;
# The comment API will display comments for users with the permission to grade the activity when the comment is associated with an activity. See [Mockup: Anonymous Comment Stream|#AnonymousCommentStream] &lt;br /&gt;
# The comment API will allow user&#039;s to post content from repositories when set to be anonymous, even if the repository could give away the user&#039;s identity (for example video). &lt;br /&gt;
# The user that is viewing the comments will see all of their comments with their user information and not anonymised. See [Mockup: Anonymous Comment Stream|#AnonymousCommentStream]&lt;br /&gt;
&lt;br /&gt;
===== Mockups =====&lt;br /&gt;
&lt;br /&gt;
====== Viewing and Adding Comments ======&lt;br /&gt;
&lt;br /&gt;
[[Image:viewcomments.png|viewcomments.png]]&lt;br /&gt;
&lt;br /&gt;
====== Video Comment ======&lt;br /&gt;
&lt;br /&gt;
[[Image:videocomment.png|videocomment.png]]&lt;br /&gt;
&lt;br /&gt;
====== File Attachment to Comment ======&lt;br /&gt;
&lt;br /&gt;
[[Image:fileattachmentcomment.png|fileattachmentcomment.png]]&lt;br /&gt;
&lt;br /&gt;
====== Anonymous Comment ======&lt;br /&gt;
&lt;br /&gt;
[[Image:anonymousComment.png|anonymousComment.png]]&lt;br /&gt;
&lt;br /&gt;
====== Anonymous Comment Stream ======&lt;br /&gt;
&lt;br /&gt;
[[Image:anonymousCommentStream.png|anonymousCommentStream.png]]&lt;br /&gt;
&lt;br /&gt;
===== Use Cases =====&lt;br /&gt;
&lt;br /&gt;
====== Teacher Uploads a File as a Comment to an Assignment Submission via Add Button ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The teacher has commented on a student’s submission offline and wants to upload the file as a submission comment and isn’t using a browser that supports drag and drop. They will upload the file via the add button and the upload repository.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is enrolled as a teacher in a course&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# A student has posted a submission&lt;br /&gt;
# The teacher has a file to upload on their desktop&lt;br /&gt;
# The user has navigated to the course&lt;br /&gt;
# Comment settings has the &#039;&#039;Allow file uploads&#039;&#039; checked&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teacher clicks on the assignment name&lt;br /&gt;
# The teacher clicks the add button below the textarea&lt;br /&gt;
# The teacher clicks the &#039;&#039;Upload repository&#039;&#039; link&lt;br /&gt;
# The teacher clicks the &#039;&#039;Choose file&#039;&#039; button&lt;br /&gt;
# The teacher selects the file from their computer&lt;br /&gt;
# The teacher clicks the &#039;&#039;Upload file&#039;&#039; button&lt;br /&gt;
# The teacher clicks the &#039;&#039;Save comment&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teachers comment is displayed in the comment display area with the file attached&lt;br /&gt;
# If more than 2 comments have been created the scroll bar appears.&lt;br /&gt;
&lt;br /&gt;
====== Teacher Uploads a File as a Comment to an Assignment Submission via Drag and Drop ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The teacher has commented on a student’s submission offline and wants to drag the file to the comment area to upload it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is enrolled as a teacher in a course&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# A student has posted a submission&lt;br /&gt;
# The teacher has a file to upload on their desktop&lt;br /&gt;
# A browser that supports drag and drop is used&lt;br /&gt;
# The user has navigated to the course&lt;br /&gt;
# Comment settings has the &#039;&#039;Allow file uploads&#039;&#039; checked&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teacher clicks on the assignment name&lt;br /&gt;
# The teacher drags the file from their pc to the drag and drop file area&lt;br /&gt;
# The teacher clicks the &#039;&#039;Save comment&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teachers comment is displayed in the comment display area with the file attached&lt;br /&gt;
# If more than 2 comments have been created the scroll bar appears.&lt;br /&gt;
&lt;br /&gt;
====== Teacher Records a Video Comment for an Assignment Submission ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The teacher wants to record a visual comment about the student’s assignment submission instead of typing or commenting on a file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is enrolled as a teacher in a course&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# A student has posted a submission&lt;br /&gt;
# The teacher has a web camera installed&lt;br /&gt;
# The site has the kaltura web cam TinyMCE button enabled&lt;br /&gt;
# The user has navigated to the course&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teacher clicks on the assignment name&lt;br /&gt;
# The teacher clicks the web cam button in the file upload area&lt;br /&gt;
# The teacher records their web cam video&lt;br /&gt;
# The teacher clicks the &#039;&#039;Save comment&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teachers comment is displayed in the comment display area with a video player to play the video&lt;br /&gt;
# If more than 2 comments have been created the scroll bar appears.&lt;br /&gt;
&lt;br /&gt;
====== Student Views More than 2 Assignment Submission Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The student is viewing the submission comments for their assignment submissions. A conversation has been going on and the student is scrolling into the history to view some of the past comments by the teacher.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is enrolled as a student in a course&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# The student has posted a submission&lt;br /&gt;
# The teacher has posted more than 1 submission comment&lt;br /&gt;
# The student has posted more than 1 submission comment&lt;br /&gt;
# The user has navigated to the course&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student clicks on the assignment name&lt;br /&gt;
# The student clicks up on the scrollbar&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# As the scroll bar goes up previously created comments are displayed&lt;br /&gt;
&lt;br /&gt;
====== Teacher Deletes a Comment With Attached Files ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The teacher wants to remove a comment they have made with files that we incorrectly attached.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is enrolled as a teacher in a course&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# A student has posted a submission&lt;br /&gt;
# The teacher has attached a file to a comment and saved it&lt;br /&gt;
# Comment settings has the &#039;&#039;Enable file uploads&#039;&#039; checked&lt;br /&gt;
# THe teacher has navigated to the course&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teacher clicks on the assignment name&lt;br /&gt;
# The teacher clicks the delete button to the right of the comment&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The comment and all file attachments are deleted&lt;br /&gt;
# The comment is removed from the screen.&lt;br /&gt;
&lt;br /&gt;
====== Student Views Assignment Submission Comments With a Screen Reader ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The student is visually impaired and reviewing the comments for their assignment submission using a screen reader.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is enrolled as a student in a course&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# A student has posted a submission&lt;br /&gt;
# The student has navigated to the course&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student skips to the main content&lt;br /&gt;
# The student tabs to the activity name&lt;br /&gt;
# The student hits the enter key&lt;br /&gt;
# The student tabs to the comment area&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student clearly understand the order of the comments&lt;br /&gt;
# &lt;br /&gt;
# ====== Student Views a Blind Marking Assignment Submission With Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The student is viewing the submission comments for their assignment submissions. A conversation has been going on and the student is scrolling into the history to view some of the past comments by the teacher.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in &lt;br /&gt;
# The user is enrolled as a student in a course &lt;br /&gt;
# An assignment has been created that allows submission comments and is set to blind marking &lt;br /&gt;
# The student has posted a submission &lt;br /&gt;
# The teacher has posted more than 1 submission comment &lt;br /&gt;
# The student has posted more than 1 submission comment &lt;br /&gt;
# The user has navigated to the course &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student clicks on the assignment name &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# As the scroll bar goes up previously created comments are displayed &lt;br /&gt;
&lt;br /&gt;
====== Teacher Views a Blind Marking Assignment Submission With Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The teacher is views a student’s submission comments for an assignment that has been set to blind marking&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in &lt;br /&gt;
# The user is enrolled as a teacher in a course &lt;br /&gt;
# An assignment has been created that allows submission comments and is set to blind marking &lt;br /&gt;
# The student has posted a submission &lt;br /&gt;
# The teacher has posted more than 1 submission comment &lt;br /&gt;
# The student has posted more than 1 submission comment &lt;br /&gt;
# The user has navigated to the course &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The teacher clicks on the assignment name &lt;br /&gt;
# The teacher clicks the &#039;&#039;View/grade all submissions&#039;&#039; link &lt;br /&gt;
# The teacher clicks on the grade icon for one of the students in the grade table &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# All comments made by the student are set to Participant and a number &lt;br /&gt;
# The teacher’s comment displays their name above it. &lt;br /&gt;
&lt;br /&gt;
==== Comments Backup and Restore ====&lt;br /&gt;
&lt;br /&gt;
===== Description =====&lt;br /&gt;
&lt;br /&gt;
Moodlerooms will update the commenting API to support files in the backup and restore process.&lt;br /&gt;
&lt;br /&gt;
===== Requirements=====&lt;br /&gt;
# If a file is attached to a comment it will be backed up with the comment following the current backup process.&lt;br /&gt;
# Anonymous comments will not be anonymous in the course backup and will be associated with the user who created the comment. &lt;br /&gt;
&lt;br /&gt;
===== Use Cases =====&lt;br /&gt;
&lt;br /&gt;
====== Site Administrator Backs up a Course with Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The site administrator wants to backup the current course with the user’s data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is set as a site administrator&lt;br /&gt;
# An assignment has been created that allows submission comments&lt;br /&gt;
# A student has posted a submission&lt;br /&gt;
# A teacher has commented on the assignment submission&lt;br /&gt;
# A student has commented on the assignment submission&lt;br /&gt;
# The site administrator has navigated to a course&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Backup&#039;&#039; link in the Settings block under the Course Administrator group&lt;br /&gt;
# The site administrator leaves the default settings&lt;br /&gt;
# The site administrator click the &#039;&#039;Next&#039;&#039; button&lt;br /&gt;
# The site administrator leaves the default settings&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Next&#039;&#039; button&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Perform backup&#039;&#039; button&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Continue&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The files attached to user comments in the backup are in the backup file&lt;br /&gt;
# If the course is restored the comments will show with the files attached to the correct comments.&lt;br /&gt;
&lt;br /&gt;
====== Site Administrator Restores a Course with Comments ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The site administrator wants to restore a course that has user’s data and comments on assignments.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in&lt;br /&gt;
# The user is set as a site administrator&lt;br /&gt;
# The site administrator has a course backup that contains the following:&lt;br /&gt;
## An assignment has been created that allows submission comments&lt;br /&gt;
## A student has posted a submission&lt;br /&gt;
## A teacher has commented on the assignment submission&lt;br /&gt;
## A student has commented on the assignment submission&lt;br /&gt;
# The site administrator is at the site level&lt;br /&gt;
# The backup file is less than 50 MB in size.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Restore&#039;&#039; link in the Settings block under Front page administration&lt;br /&gt;
# The site administrator drags the backup file to the drag and drop file area.&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Restore&#039;&#039; button&lt;br /&gt;
# The include comments is checked under backup settings&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Continue&#039;&#039; button&lt;br /&gt;
# The site administrator selects a category radio button under Restore as a new course&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Continue&#039;&#039; button under Restore as a new course&lt;br /&gt;
# The site administrator keeps the default settings&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Next&#039;&#039; button&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Next&#039;&#039; button&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Perform restore&#039;&#039; button&lt;br /&gt;
# The site administrator clicks the &#039;&#039;Continue&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The site administrator can view the comments within the assignment.&lt;br /&gt;
# The comments have files correctly attached to each comment.&lt;br /&gt;
&lt;br /&gt;
==== Comment Message Output ====&lt;br /&gt;
&lt;br /&gt;
===== Description =====&lt;br /&gt;
&lt;br /&gt;
When a new comments is created it is not communicated to the student or teacher. This makes comments less useful for many plugins that user comments as an important communication to both users. Comments will be updated to have a message output event that message outputs can display and a student or teacher can set to send to each message output type they want.&lt;br /&gt;
&lt;br /&gt;
===== Requirements =====&lt;br /&gt;
&lt;br /&gt;
# A new message output event will be created for comments. &lt;br /&gt;
# All comments when created will trigger a comment event that the message outputs can listen for.&lt;br /&gt;
# The comment message event sender will be set to the user that made the comment&lt;br /&gt;
# The comment message event recipient will be all users with the role to view the comment who are not the comment creator.&lt;br /&gt;
# The comment message event subject will be “New comment for &amp;lt;context&amp;gt;” where context is the location that the comment was created:&lt;br /&gt;
## Comment block - the course or activity the block is associated with&lt;br /&gt;
## Assignment submission - the assignment the comment is associated with&lt;br /&gt;
## Blog comment - the blog the comment is associated with.&lt;br /&gt;
# The comments message event full message will contain the following:&lt;br /&gt;
## The full comment in plaintext&lt;br /&gt;
## Text stating “View original message” that is linked to url to the comment in the location in Moodle where the user can view the comment (Comment block in course or assignment submission)&lt;br /&gt;
# The comment message event full message format will be plaintext.&lt;br /&gt;
# The comments message event short message will contain the following:&lt;br /&gt;
## Up to 80 character of the original comment in plain text&lt;br /&gt;
## The text “View original message at &amp;lt;url&amp;gt;” where the &amp;lt;url&amp;gt; is the url to the location in Moodle where the user can view the comment&lt;br /&gt;
# By default the message output settings for the comments event will be enabled for: (see [[#User_Message_Output_Settings|Mockup: User Message Output Settings]])&lt;br /&gt;
## Email&lt;br /&gt;
### When logged in&lt;br /&gt;
### When not logged in&lt;br /&gt;
## Alert&lt;br /&gt;
### When logged in&lt;br /&gt;
### When not logged in&lt;br /&gt;
## Streams &lt;br /&gt;
### When logged in&lt;br /&gt;
### When not logged in&lt;br /&gt;
&lt;br /&gt;
===== Mockups =====&lt;br /&gt;
&lt;br /&gt;
====== User Message Output Settings ======&lt;br /&gt;
&lt;br /&gt;
[[Image:commentmessageoutput.png|commentmessageoutput.png]]&lt;br /&gt;
&lt;br /&gt;
===== Use cases =====&lt;br /&gt;
&lt;br /&gt;
====== Student Accesses an Alert After a Teacher Posts a Comment to an Advanced Forum in Joule Grader ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A teacher posts a comment for a student’s submission to an activity in the Joule grader and the student receives an alert when they login.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# User is logged in &lt;br /&gt;
# User is enrolled in a course as a student&lt;br /&gt;
# User has posted a submission to an advanced forum&lt;br /&gt;
# A teacher has posted an activity comment in the Joule grader for the student and activity&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student views the front page &lt;br /&gt;
# The student sees a number of alerts in the upper right of the page&lt;br /&gt;
# The student clicks on the icon&lt;br /&gt;
# The student sees a Joule grader comment for an activity&lt;br /&gt;
# The student clicks on the link to the full comment in the Joule grader&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student is show the activity in the Joule grader and the comment shows in the Activity comments area&lt;br /&gt;
&lt;br /&gt;
====== Student Accesses an Alert After a Teacher Posts a Comment to an Assignment in Joule Grader ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A teacher posts a comment for a student’s submission to an activity in the Joule grader and the student receives an alert when they login.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# User is logged in &lt;br /&gt;
# User is enrolled in a course as a student&lt;br /&gt;
# User has posted a submission to an Assignment&lt;br /&gt;
# A teacher has posted an activity comment in the Joule grader for the student and activity&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student views the front page &lt;br /&gt;
# The student sees a number of alerts in the upper right of the page&lt;br /&gt;
# The student clicks on the icon&lt;br /&gt;
# The student sees a Joule grader comment for an activity&lt;br /&gt;
# The student clicks on the link to the full comment in the Joule grader&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student is show the activity in the Joule grader and the comment shows in the Activity comments area&lt;br /&gt;
&lt;br /&gt;
====== Student Changes Their Comments Alert Message Output ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A student changes their message outputs to not display alerts when they are online for comments.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# User is logged in &lt;br /&gt;
# User is enrolled in a course as a student&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student clicks on the &#039;&#039;My profile&#039;&#039; link&lt;br /&gt;
# The student selects message outputs in the settings block&lt;br /&gt;
# The student clicks on the alert when online for the comments setting.&lt;br /&gt;
# The student clicks the &#039;&#039;Save changes&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The next comment in the Joule grader the student receives and email.&lt;br /&gt;
&lt;br /&gt;
====== Student Changes Their Offline Comments Email Message Output Setting ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A student changes their message outputs to receive emails when they are offline for comments.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is logged in &lt;br /&gt;
# The user is enrolled in a course as a student&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student clicks on the &#039;&#039;My profile&#039;&#039; link&lt;br /&gt;
# The student selects &#039;&#039;Message outputs&#039;&#039; in the settings block&lt;br /&gt;
# The student clicks on the email when offline for the Comments setting.&lt;br /&gt;
# The student clicks the &#039;&#039;Save changes&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The next comment on the student’s assignment submission will be emailed to the student if they are not logged into Moodle.&lt;br /&gt;
&lt;br /&gt;
====== Student Clicks the URL to the Comment in the Message Output Email ======&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The student has received a comment message output in their email. The student clicks on the link to view the comment in Moodle.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Preconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The user is not logged in&lt;br /&gt;
# The user received an email notifying them that a new comment exists&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Steps&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student clicks on the link in the email&lt;br /&gt;
# The student enters their username&lt;br /&gt;
# The student enters their password&lt;br /&gt;
# The student clicks the &#039;&#039;Login&#039;&#039; button&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Postconditions&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# The student is taken to the Moodle page where the comment can be read&lt;br /&gt;
&lt;br /&gt;
=== Document Information ===&lt;br /&gt;
&lt;br /&gt;
==== Revision Summary ====&lt;br /&gt;
&lt;br /&gt;
==== Revision History ====&lt;br /&gt;
&lt;br /&gt;
* Jason Hardin 20130131: Split out Joule features from Moodle features. Added new mockups for Moodle specific interfaces. Updated the Comments update use cases to include deletion and screen readers.&lt;br /&gt;
* Jason Hardin 20130205: Added message output event information. Added a new use case for navigating to the comment in Moodle from email, and updated screen shots to remove old information and add some more descriptive information.&lt;br /&gt;
* Jason Hardin 20130212: Removed the HTML editor setting and migrated video and audio comments to using the file picker.&lt;br /&gt;
* Jason Hardin 20130221: Added Alerts and streams back to the specification as these will be released to the Moodle Community. &lt;br /&gt;
* Jason Hardin 20130221: Added anonymous comment support to allow for Blind marking in assignment submission comments. See tracker ticket [https://tracker.moodle.org/browse/MDL-37497| MDL-37497]&lt;br /&gt;
* Jason Hardin 20130222: Moved Joule Comments changes back into this specification because Moodlerooms will be releasing all Joule features that caused the specification separation.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
[https://moodle.org/mod/forum/discuss.php?d=221619| Comments Forum Discussion]&lt;br /&gt;
[[Category: Project]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Cohorts&amp;diff=64546</id>
		<title>Cohorts</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Cohorts&amp;diff=64546"/>
		<updated>2025-02-10T07:59:39Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Cohorts&lt;br /&gt;
|state = Work in progress&lt;br /&gt;
|tracker = MDL-21781&lt;br /&gt;
|discussion = n/a&lt;br /&gt;
|assignee = [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]]&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
=Goals=&lt;br /&gt;
Site-wide groups (aka cohorts) is one of the most requested missing features.&lt;br /&gt;
# Simplify manual enrolments - instead of enrolling students one by one, it would be possible to enrol a cohort with single click.&lt;br /&gt;
# Cohort enrolment plugin - new enrolment plugin synchronising users in cohort with enrolments in a course (including role assignment and group membership)&lt;br /&gt;
# Synchronisation with external systems - some external systems do not know the actual courses, they only contain some user groups, at present we do not have a simple way to reuse these groups in Moodle.&lt;br /&gt;
# Partially replace meta courses&lt;br /&gt;
# Replace category enrolments - category enrolments have major design issues and are not compatible with incoming enrolment changes.&lt;br /&gt;
=DB tables=&lt;br /&gt;
Table &#039;&#039;cohort&#039;&#039; definition of site-wide groups (aka cohorts)&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;id&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;contextid&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| foreign key, references context.id&lt;br /&gt;
|-&lt;br /&gt;
| name&lt;br /&gt;
| char(254)&lt;br /&gt;
| &lt;br /&gt;
| human readable cohort name&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;idnumber&#039;&#039;&#039;&lt;br /&gt;
| char(100)&lt;br /&gt;
| &lt;br /&gt;
| unique identifier of the cohort, can be used in external systems&lt;br /&gt;
|-&lt;br /&gt;
| description&lt;br /&gt;
| text&lt;br /&gt;
| &lt;br /&gt;
| longer description&lt;br /&gt;
|-&lt;br /&gt;
| descriptionformat&lt;br /&gt;
| int(2)&lt;br /&gt;
| &lt;br /&gt;
| text format&lt;br /&gt;
|-&lt;br /&gt;
| component&lt;br /&gt;
| char(100)&lt;br /&gt;
| &lt;br /&gt;
| component name of a plugin responsible for assignment of users (ex: auth_ldap, etc.), NULL means manual assignments&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| timestamp, creation date&lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| timestamp, last modification&lt;br /&gt;
|}&lt;br /&gt;
Context specified can be system or course category level, defining of cohort a course context would not make much sense.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Table &#039;&#039;cohort_members&#039;&#039; stores cohort members&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;id&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;cohortid&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| foreign key, references cohort.id&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;userid&#039;&#039;&#039; &lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| foreign key, references user.id&lt;br /&gt;
|-&lt;br /&gt;
| timeadded&lt;br /&gt;
| int(10)&lt;br /&gt;
| &lt;br /&gt;
| timestamp, when added&lt;br /&gt;
|}&lt;br /&gt;
=New capabilities=&lt;br /&gt;
* moodle/cohort:assign - add/delete members (only for manual assignment cohorts with source == null)&lt;br /&gt;
* moodle/cohort:manage -add/delete/move cohorts&lt;br /&gt;
* moodle/cohort:view - view membership and use cohort elsewhere&lt;br /&gt;
Context id defined in cohort table is used for access control only, the cohort may be actually used in any context (this may happen when moving courses, categories or cohorts).&lt;br /&gt;
=User interface=&lt;br /&gt;
# Cohort edit link in CONTEXT_SYSTEM and each CONTEXT_COURSECAT- most probably from the settings block&lt;br /&gt;
# Option for manual cohort enrolment - part of new enrolment UI&lt;br /&gt;
# New UI in cohort enrolment plugin&lt;br /&gt;
# New options in group creation UI&lt;br /&gt;
# New options for sync with external groups in auth or enrol plugins&lt;br /&gt;
=Implementation steps=&lt;br /&gt;
# add db tables and cohort membership UI&lt;br /&gt;
# add option to assign role to all cohort users (one time only, no sync)&lt;br /&gt;
# enrolment rewrite&lt;br /&gt;
# cohort enrolment plugin&lt;br /&gt;
=Upgrade=&lt;br /&gt;
Cohorts are designed to replace course category enrolments because the new enrolment plugin is not compatible with this.&lt;br /&gt;
=See also=&lt;br /&gt;
* [[Enrolment rewrite and role tweaks proposal]]&lt;br /&gt;
* [[New permissions evaluation in 2.0]]&lt;br /&gt;
* [[New permission overriding UI]]&lt;br /&gt;
* [[New enrolments in 2.0]]&lt;br /&gt;
[[Category:Roles]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Caliper&amp;diff=64545</id>
		<title>Caliper</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Caliper&amp;diff=64545"/>
		<updated>2025-02-10T07:57:35Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The Caliper Logstore component uses the Moodle Logging interface to capture user events and emit them to a Caliper event store.  The [https://www.imsglobal.org/caliper Caliper Framework] is a specification from IMS Global which provides a data representation of learning activities and an API for transmitting these to an event store for later analysis.  Metric profiles are used to describe different types of learning activity, allowing representations to be matched against the nature of the activity.  Events may be sent immediately to the event store, or captured for sending later in batches.&lt;br /&gt;
&lt;br /&gt;
== Events supported ==&lt;br /&gt;
&lt;br /&gt;
The following table shows the mapping of Moodle URLs to Caliper events supported by the current version of this component:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Supported Caliper Events&lt;br /&gt;
|-&lt;br /&gt;
!Metric Profile&lt;br /&gt;
!Action&lt;br /&gt;
!Moodle URL&lt;br /&gt;
|-&lt;br /&gt;
|rowspan=&amp;quot;2&amp;quot;|Session&lt;br /&gt;
|Logged In&lt;br /&gt;
|\core\event\user_loggedin&lt;br /&gt;
|-&lt;br /&gt;
|Logged Out&lt;br /&gt;
|\core\event\user_loggedout&lt;br /&gt;
|-&lt;br /&gt;
|Navigation&lt;br /&gt;
|Navigated To&lt;br /&gt;
|\core\event\course_viewed&lt;br /&gt;
|-&lt;br /&gt;
|View&lt;br /&gt;
|Viewed&lt;br /&gt;
|&lt;br /&gt;
\mod_book\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_chat\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_choice\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_data\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_facetoface\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_feedback\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_folder\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_forum\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_forum\event\user_report_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_glossary\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_imscp\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_lesson\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_lti\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_page\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_quiz\event\attempt_reviewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_quiz\event\attempt_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_quiz\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_resource\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_scorm\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_survey\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_url\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_wiki\event\course_module_viewed&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_workshop\event\course_module_viewed&lt;br /&gt;
|-&lt;br /&gt;
|rowspan=&amp;quot;2&amp;quot;|Assessment&lt;br /&gt;
|Started&lt;br /&gt;
|\mod_quiz\event\attempt_started&lt;br /&gt;
|-&lt;br /&gt;
|Submitted&lt;br /&gt;
|&lt;br /&gt;
\mod_quiz\event\attempt_submitted&amp;lt;br /&amp;gt;&lt;br /&gt;
\mod_assign\event\assessable_submitted&lt;br /&gt;
|-&lt;br /&gt;
|Outcome&lt;br /&gt;
|Graded&lt;br /&gt;
|\mod_assign\event\submission_graded&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== How does it work? ==&lt;br /&gt;
&lt;br /&gt;
The component adopts the same implementation method as the logstore component for [https://moodle.org/plugins/logstore_xapi xAPI].  It is made up of three parts: an [https://github.com/LearningLocker/Moodle-Log-Expander Expander], a Translator, and an Emitter.  Each log entry follows a six step process before finally reaching the event store:&lt;br /&gt;
&lt;br /&gt;
# The component passes the log entry from the logstore_standard_log to the Expander.&lt;br /&gt;
# The Expander expands the log entry with data from the Moodle database.&lt;br /&gt;
# The component passes the expanded event from to the Translator.&lt;br /&gt;
# The Translator translates the expanded event to Caliper metric profile options.&lt;br /&gt;
# The component passes the translated event to the Emitter.&lt;br /&gt;
# The Emitter emits the event to the event store using the Caliper Sensor API.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
The component can be installed onto a Moodle 2.7+ instance as follows:&lt;br /&gt;
&lt;br /&gt;
# [https://moodle.org/plugins/logstore_caliper Download the component].&lt;br /&gt;
# Log into your instance of Moodle as a System Administrator.&lt;br /&gt;
# Go to &#039;&#039;/admin/tool/installaddon/&#039;&#039; on your Moodle instance.&lt;br /&gt;
# Drag and drop your download from step 1.&lt;br /&gt;
# Click &#039;&#039;Install plugin from the ZIP file&#039;&#039;.&lt;br /&gt;
# Click &#039;&#039;Install plugin!&#039;&#039;.&lt;br /&gt;
# Click &#039;&#039;Upgrade Moodle database now&#039;&#039;.&lt;br /&gt;
# Click &#039;&#039;Continue&#039;&#039;.&lt;br /&gt;
# Complete the component&#039;s settings page:&lt;br /&gt;
#* &#039;&#039;Event Store URL&#039;&#039;;&lt;br /&gt;
#* &#039;&#039;API Key&#039;&#039;;&lt;br /&gt;
#* &#039;&#039;Send statements immediately to event store?&#039;&#039;;&lt;br /&gt;
#* &#039;&#039;Batch size&#039;&#039;.&lt;br /&gt;
# Click &#039;&#039;Save changes&#039;&#039;.&lt;br /&gt;
# Go to &#039;&#039;/admin/settings.php?section=managelogging&#039;&#039; on your Moodle instance.&lt;br /&gt;
# Enable the &#039;&#039;Caliper log store&#039;&#039; component (use the &#039;&#039;Settings&#039;&#039; option to update the component&#039;s settings values).&lt;br /&gt;
&lt;br /&gt;
NB If zip installation is disabled, you can unzip the zip file to &#039;&#039;/admin/tool/log/store&#039;&#039; instead of steps 3 to 5 above.&lt;br /&gt;
&lt;br /&gt;
== About the Contributors ==&lt;br /&gt;
&lt;br /&gt;
This plugin was contributed by the Blackboard Product Development team in collaboration with Stephen Vickers. Blackboard is an education technology company dedicated to bringing excellent online teaching to institutions across the globe. We serve colleges and universities, schools and organizations by supporting the software that educators use to manage and deliver instructional content to learners in virtual classrooms. We are proud to be a Moodle Partner company.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=CSS_styles_moz.css&amp;diff=64544</id>
		<title>CSS styles moz.css</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=CSS_styles_moz.css&amp;diff=64544"/>
		<updated>2025-02-10T07:54:33Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
== styles_moz.css == &lt;br /&gt;
This [[CSS]] file uses the non-standard Mozilla CSS extensions to add round corners to the current theme. Styles are organised into the following sections: core, header, footer, admin, blocks, calendar, course, doc, login, message, tabs, user, various modules&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Core&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 .headingblock {&lt;br /&gt;
  -moz-border-radius:3px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .notifyproblem {&lt;br /&gt;
  -moz-border-radius:10px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .notifysuccess {&lt;br /&gt;
  -moz-border-radius:10px;&lt;br /&gt;
 }&lt;br /&gt;
 .generalbox {&lt;br /&gt;
  -moz-border-radius-topleft:3px;&lt;br /&gt;
  -moz-border-radius-topright:3px;&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .generalboxcontent {&lt;br /&gt;
  -moz-border-radius-topleft:3px;&lt;br /&gt;
  -moz-border-radius-topright:3px;&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .noticebox {&lt;br /&gt;
  -moz-border-radius:5px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .informationbox {&lt;br /&gt;
  -moz-border-radius-topleft:3px;&lt;br /&gt;
  -moz-border-radius-topright:3px;&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .informationboxcontent {&lt;br /&gt;
  -moz-border-radius-topleft:3px;&lt;br /&gt;
  -moz-border-radius-topright:3px;&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .sitetopiccontent {&lt;br /&gt;
  -moz-border-radius:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .headingblock {&lt;br /&gt;
  -moz-border-radius:3px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .categorybox, .categoryboxcontent, &lt;br /&gt;
 .coursebox, .courseboxcontent {&lt;br /&gt;
  -moz-border-radius:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* kept for backward compatibility with some non-standard modules&lt;br /&gt;
   which use these classes for various things */&lt;br /&gt;
 .generaltab, .generaltabinactive{&lt;br /&gt;
  -moz-border-radius-topleft:15px;&lt;br /&gt;
  -moz-border-radius-topright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .generaltabselected {&lt;br /&gt;
  -moz-border-radius-topleft:15px;&lt;br /&gt;
  -moz-border-radius-topright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Blocks&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 .sideblock.hidden {&lt;br /&gt;
  -moz-border-radius: 0px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .sideblock .content {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .block_course_summary, .block_course_summary .content {&lt;br /&gt;
  -moz-border-radius:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .editing .block_course_summary .content {&lt;br /&gt;
  -moz-border-radius-topleft:0;&lt;br /&gt;
  -moz-border-radius-topright:0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Calendar&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 #calendar .eventlist .event {&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 #calendar .eventlist .event .side {&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 #calendar .eventlist .event .description {&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 #calendar .maincalendar,&lt;br /&gt;
 #calendar .sidecalendar&lt;br /&gt;
 {&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 #calendar .maincalendar .filters table,&lt;br /&gt;
 #calendar .sidecalendar .filters table,&lt;br /&gt;
 .sideblock.block_calendar_month .filters table&lt;br /&gt;
 {&lt;br /&gt;
  -moz-border-radius:4px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 table.minicalendar {&lt;br /&gt;
  -moz-border-radius:10px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 table.minicalendar td {&lt;br /&gt;
  -moz-border-radius:4px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Course&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 body#course-user .section {&lt;br /&gt;
  -moz-border-radius:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Login&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 .loginbox {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .loginbox .content.left {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
 }&lt;br /&gt;
 .loginbox .content.right {&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;User&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 .userinfobox {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .groupinfobox {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
 #user-view .left {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Modules: Forum&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 .forumpost {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .forumpost .side {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .forumpost .content {&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .forumpost .message {&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Modules: Glossary&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 .categoryheader {&lt;br /&gt;
  -moz-border-radius-topleft:15px;&lt;br /&gt;
  -moz-border-radius-topright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .glossaryformatheader {&lt;br /&gt;
  -moz-border-radius-topleft:15px;&lt;br /&gt;
  -moz-border-radius-topright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .entryboxheader {&lt;br /&gt;
  -moz-border-radius-topleft:10px;&lt;br /&gt;
  -moz-border-radius-topright:10px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .entrybox {&lt;br /&gt;
  -moz-border-radius-bottomleft:10px;&lt;br /&gt;
  -moz-border-radius-bottomright:10px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .glossarypost {&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .glossarypost .side {&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .encyclopedia .entrylowersection {&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
 .glossarycomment {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .glossarycomment .side {&lt;br /&gt;
  -moz-border-radius-bottomleft:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 .glossarycomment .entry {&lt;br /&gt;
  -moz-border-radius-bottomright:20px;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Modules: Journal&amp;lt;/h3&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 #mod-journal-view .feedbackbox {&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;br /&gt;
 #mod-journal-view .feedbackbox .side {&lt;br /&gt;
  -moz-border-radius-bottomleft:15px;&lt;br /&gt;
 }&lt;br /&gt;
 #mod-journal-view .feedbackbox .entrycontent {&lt;br /&gt;
  -moz-border-radius-bottomright:15px;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blog_2.0&amp;diff=64543</id>
		<title>Blog 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blog_2.0&amp;diff=64543"/>
		<updated>2025-02-10T07:51:27Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PROJECT STATE: Complete&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;MAIN TRACKER ISSUE&#039;&#039;&#039;: MDL-19676 Blog 2.0 improvements&lt;br /&gt;
* &#039;&#039;&#039;DISCUSSION AND COMMENTS&#039;&#039;&#039;: http://moodle.org/mod/forum/discuss.php?d=133348&lt;br /&gt;
&lt;br /&gt;
== Description of improvements ==&lt;br /&gt;
=== Who can view blog entries? ===&lt;br /&gt;
Blog entries are either in draft mode (only the author can view it), or in public mode. In public mode, everyone on the entire site can view the blog entry. &lt;br /&gt;
&lt;br /&gt;
Before 2.0 there was an attempt to restrict who can view certain blog entries, based on course enrolment and capabilities. However, after extensive discussion and feasibility testing it became clear that this could lead to serious performance and usability issues on large sites, and was turning the blog into something more akin to a forum. It was thus decided to make all blogs public. (See MDL-19676)&lt;br /&gt;
&lt;br /&gt;
This simplification means that sites using the old BLOG_GROUP_LEVEL and BLOG_COURSE_LEVEL and values of $CFG-&amp;gt;bloglevel have to perform an special upgrade which copies all the site&#039;s blog entries into a special &amp;quot;blog-type&amp;quot; forum in each course in which the blog entry&#039;s author is enrolled, then disables blogging at site level.&lt;br /&gt;
&lt;br /&gt;
Capabilities:&lt;br /&gt;
*moodle/blog:view&lt;br /&gt;
*moodle/blog:viewdrafts&lt;br /&gt;
&lt;br /&gt;
=== Associations ===&lt;br /&gt;
A blog entry can optionally be associated with a course. This makes it possible for a user to blog &amp;quot;about&amp;quot; that course. All blog entries associated in that way can be viewed on a page like blog/index.php?courseid=3. This type of filtering of blog entries does not take into account course enrolments.&lt;br /&gt;
&lt;br /&gt;
Additionally, blog entries can be associated with an activity module.&lt;br /&gt;
&lt;br /&gt;
This requires the creation of a new table, in which the associations are recorded.&lt;br /&gt;
Tracker issue: MDL-14408&lt;br /&gt;
&lt;br /&gt;
Capabilities: &lt;br /&gt;
*moodle/blog:associatecourse&lt;br /&gt;
*moodle/blog:associatemodule&lt;br /&gt;
&lt;br /&gt;
=== Improved navigation ===&lt;br /&gt;
Before 2.0, the navigation for any listing of blog entries was either &amp;quot;Site &amp;gt; User &amp;gt; Blogs&amp;quot; (for a user&#039;s blog entries) or &amp;quot;Site &amp;gt; Blogs&amp;quot; for the whole site&#039;s blog entries, optionally filtered by tag. With the new association features, we need a better way to display what type of blog listing we are looking at, based on the parameters passed to blog/index.php. The navigation should also reflect additional filters such as tag and search.&lt;br /&gt;
&lt;br /&gt;
=== External blogs ===&lt;br /&gt;
A user can specify external blogs which publish an RSS/ATOM feed. This feed is then checked periodically through a cron task, and entries are copied into the user&#039;s blog in Moodle, as read-only entries.&lt;br /&gt;
&lt;br /&gt;
This synchronisation checks if external entries have been modified or deleted since the last sync, and updates the Moodle entries accordingly.&lt;br /&gt;
&lt;br /&gt;
These external blogs are a user preference, and two types of tags can be added to each of them: &amp;quot;Filter tags&amp;quot; and &amp;quot;Automatic tags&amp;quot;:&lt;br /&gt;
*Filter tags are used to filter the external blog entries that get copied into Moodle. They must match the tags used by that external blog. An external entry will be selected if it has at least one of the filter tags. (Tags are called &amp;quot;categories&amp;quot; in RSS feeds)&lt;br /&gt;
*Automatic tags are automatically added to each blog entry copied into Moodle from an external blog that uses such tags.&lt;br /&gt;
&lt;br /&gt;
This requires the creation of a new DB table.&lt;br /&gt;
Tracker issue: MDL-19683&lt;br /&gt;
&lt;br /&gt;
Capabilities:&lt;br /&gt;
*moodle/blog:manageexternal&lt;br /&gt;
&lt;br /&gt;
=== Search blog entries ===&lt;br /&gt;
It is now possible to search blog entries using a search box. The results maintain the current context, so that if you are viewing a list of blog entries for a particular user, entering a term in the search box will return only the blog entries for that user that match the search term. The search term also appears in the navigation breadcrumbs.&lt;br /&gt;
&lt;br /&gt;
Tracker issue: MDL-19686&lt;br /&gt;
&lt;br /&gt;
Capabilities:&lt;br /&gt;
*moodle/blog:search&lt;br /&gt;
&lt;br /&gt;
=== Contextual blog menu ===&lt;br /&gt;
Previously, the &amp;quot;blog menu&amp;quot; block was the same on every page on which it appeared. In 2.0 it changes depending on which page you are. For example, if you are on course/view.php, it will include a link to blog entries associated with that course. Also, the link for adding a new entry will include the courseid, making the course association automatically pre-selected in the blog entry edit form.&lt;br /&gt;
&lt;br /&gt;
Tracker issue: MDL-19687&lt;br /&gt;
&lt;br /&gt;
=== File attachments ===&lt;br /&gt;
The [[File_API|new file manager]] must be implemented to allow for multiple file attachments per blog entry.&lt;br /&gt;
&lt;br /&gt;
Tracker issue: MDL-19744&lt;br /&gt;
&lt;br /&gt;
=== Comments ===&lt;br /&gt;
The new [[Comments_2.0|Comments API]] makes it possible for anyone having the correct capability to comment on blog entries.&lt;br /&gt;
&lt;br /&gt;
Tracker issue: MDL-8776&lt;br /&gt;
&lt;br /&gt;
=== New &amp;quot;Recent blog entries&amp;quot; block ===&lt;br /&gt;
This block can be configured to display the last N blog entries, filtered by context. For example, if you are viewing an assignment activity, this block would display the last N blog entries that are associated with that assignment.&lt;br /&gt;
&lt;br /&gt;
Tracker issue: MDL-19688&lt;br /&gt;
&lt;br /&gt;
== Potential problems and limitations ==&lt;br /&gt;
&lt;br /&gt;
===Upgrade from &amp;quot;Users can only see blogs for people who share a course&amp;quot;===&lt;br /&gt;
&lt;br /&gt;
This mode was always a slightly quirky and uncomfortable hack.  It was mostly useful for sites with very distinct courses and users, such as those where each course consists of the employees from a separate company, and My Moodle was used to hide the companies from each other.  However, for the general case, the main problem is that you see ALL blog entries from those people, not just ones that are about your courses.  &lt;br /&gt;
&lt;br /&gt;
This mode has no direct equivalent in Moodle 2.0 because we have resolved not to emulate &amp;quot;course-like&amp;quot; modes within a system that is at system level, and outside the courses.  This helps understanding of the blog system, simplifies the implementation and improves performance.  &lt;br /&gt;
&lt;br /&gt;
However some people may be using that mode so we do need to provide an upgrade path for them.&lt;br /&gt;
&lt;br /&gt;
Informationally, the idea of just seeing all the blogs from people who are in your course is the same as a course forum. &lt;br /&gt;
&lt;br /&gt;
So a possible upgrade would be to do this:&lt;br /&gt;
 If the mode is set to &amp;quot;Users can only see blogs for people who share a course&amp;quot; then&lt;br /&gt;
   Set the new mode to &amp;quot;Users can only see their own blog&amp;quot;&lt;br /&gt;
   Foreach user who has a blog &lt;br /&gt;
     Foreach course that user is enrolled in &lt;br /&gt;
        If a &amp;quot;Course blogs (recovered)&amp;quot; forum doesn&#039;t exist yet in the course (section 0) then create one&lt;br /&gt;
        Foreach blog entry that the user created &lt;br /&gt;
           Create a new discussion from the blog post with the same dates, attachments etc&lt;br /&gt;
&lt;br /&gt;
This way no data is lost.  The teachers can choose to delete the whole forum if they choose to.  The original blog entries should not be touched.&lt;br /&gt;
&lt;br /&gt;
== DB Structure ==&lt;br /&gt;
2 new tables need to be added: blog_external and blog_association&lt;br /&gt;
&lt;br /&gt;
=== blog_external ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this external blog.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The owner of the external blog&lt;br /&gt;
|-&lt;br /&gt;
| name&lt;br /&gt;
| char(255)&lt;br /&gt;
|&lt;br /&gt;
| A descriptive name for the external blog. Automatically fetched during initial import, can be overridden.&lt;br /&gt;
|-&lt;br /&gt;
| description&lt;br /&gt;
| text(small)&lt;br /&gt;
|&lt;br /&gt;
| A long description of the external blog. Automatically fetched during initial import, can be overridden.&lt;br /&gt;
|-&lt;br /&gt;
| url&lt;br /&gt;
| text(small)&lt;br /&gt;
|&lt;br /&gt;
| The URL to the external blog (e.g. http://moodle.org/rss.xml)&lt;br /&gt;
|-&lt;br /&gt;
| failedlastsync&lt;br /&gt;
| int(1)&lt;br /&gt;
|&lt;br /&gt;
| Whether or not the last synchronisation failed&lt;br /&gt;
|-&lt;br /&gt;
| timemodified&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| timefetched&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The last time the entries from this external blog were fetched by Moodle.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== blog_association ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Default&lt;br /&gt;
! Info&lt;br /&gt;
|-&lt;br /&gt;
| id&lt;br /&gt;
| int(10)&lt;br /&gt;
| auto-incrementing&lt;br /&gt;
| The unique ID for this blog entry&amp;lt;-&amp;gt;contextid association.&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The context id defined in context table - identifies the instance of the course or plugin associated with the blog entry.&lt;br /&gt;
|-&lt;br /&gt;
| blogid&lt;br /&gt;
| int(10)&lt;br /&gt;
|&lt;br /&gt;
| The id of the blog entry (from the post table) being associated with a course or module instance&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Upgrade process ==&lt;br /&gt;
The only task required by the upgrade process is to install the new DB tables.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
*[[Blogs|Early wishlist]]&lt;br /&gt;
*[[Student_projects/Blog_improvements|2008 GSoC project addressing some of these improvements]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Blog]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks/Appendix_A&amp;diff=64542</id>
		<title>Blocks/Appendix A</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks/Appendix_A&amp;diff=64542"/>
		<updated>2025-02-10T07:50:37Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
== Appendix A: &#039;&#039;block_base&#039;&#039; Reference ==&lt;br /&gt;
{{main|Blocks}}&lt;br /&gt;
This Appendix will discuss the base class &#039;&#039;&#039;block_base&#039;&#039;&#039; from which all other block classes derive, and present each and every method that can be overridden by block developers in detail. Methods that should &#039;&#039;&#039;not&#039;&#039;&#039; be overridden are explicitly referred to as such. After reading this Appendix, you will have a clear understanding of every method which you should or could override to implement functionality for your block.&lt;br /&gt;
&lt;br /&gt;
The methods are divided into three categories:&lt;br /&gt;
:#[[Blocks/Appendix_A#Methods_you_can_freely_use_and_override:|those you may use and override in your block]];&lt;br /&gt;
:#[[Blocks/Appendix_A#Methods_which_you_should_not_override_but_may_want_to_use:|those that you may &#039;&#039;&#039;not&#039;&#039;&#039; override but might want to use]];&lt;br /&gt;
:#[[Blocks/Appendix_A#Methods_which_you_should_not_override_and_not_use_at_all:|those internal methods that should &#039;&#039;&#039;neither&#039;&#039;&#039; be used &#039;&#039;&#039;nor&#039;&#039;&#039; overridden]].&lt;br /&gt;
In each category, methods are presented in alphabetical order.&lt;br /&gt;
&lt;br /&gt;
== Methods you can freely use and override: ==&lt;br /&gt;
&lt;br /&gt;
{{Moodle 1.7}}&lt;br /&gt;
=== after_install() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function after_install() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available between Moodle 1.7 and Moodle 1.9&lt;br /&gt;
&lt;br /&gt;
This method is designed to be overridden by block subclasses, and allows you to specify a set of tasks to be executed after the block is installed.  For example, you may wish to store the date on which the block was installed.  However, each database type has its own way of getting the current date, and when using XMLDB to install your block, these operations are also unsupported. So the best way to complete such a task while maintaining database abstraction is to use XMLDB to install the block, and then use the after_install() method to perform the insertion before the block is used.&lt;br /&gt;
&lt;br /&gt;
Please note that after_install() is called once per block, not once per instance.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
The after_install() method is no longer present in Moodle 2.0. Instead, you should use an install.php file, located within your /blocks/&amp;lt;yourblock&amp;gt;/db/ folder, to perform these actions.&lt;br /&gt;
&lt;br /&gt;
=== applicable_formats() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function applicable_formats() {&lt;br /&gt;
  // Default case: the block can be used in courses and site index, but not in activities&lt;br /&gt;
  return array(&lt;br /&gt;
    &#039;all&#039; =&amp;gt; true, &lt;br /&gt;
    &#039;mod&#039; =&amp;gt; false,&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to control which pages your block can be added to. Page formats are formulated from the full path of the script that is used to display that page. You should return an array with the keys being page format names and the values being booleans (true or false). Your block is only allowed to appear in those formats where the value is true.&lt;br /&gt;
Example format names are: &#039;&#039;&#039;course-view&#039;&#039;&#039;, &#039;&#039;&#039;site-index&#039;&#039;&#039; (this is an exception, referring front page of the Moodle site), &#039;&#039;&#039;course-format-weeks&#039;&#039;&#039; (referring to a specific course format), &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; (referring to the quiz module) and &#039;&#039;&#039;all&#039;&#039;&#039; (this will be used for those formats you have not explicitly allowed or disallowed).&lt;br /&gt;
&lt;br /&gt;
The full matching rules are:&lt;br /&gt;
&lt;br /&gt;
# Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
# The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
# The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
# The order that the format names appear does not make any difference.&lt;br /&gt;
The format name for the Dashboard (or My Moodle in earlier versions) is &#039;&#039;&#039;my&#039;&#039;&#039;.&lt;br /&gt;
=== before_delete() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function before_delete() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.7 and later&lt;br /&gt;
&lt;br /&gt;
This method is called when an administrator removes a block from the Moodle installation, immediately before the relevant database tables are deleted.  It allows block authors to perform any necessary cleanup - removing temporary files and so on - before the block is deleted.&lt;br /&gt;
&lt;br /&gt;
=== instance_create() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_create() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
Do any additional initialization you may need at the time a new block instance is created.&lt;br /&gt;
&lt;br /&gt;
=== instance_copy() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_copy($fromid) {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 2.9 and later&lt;br /&gt;
&lt;br /&gt;
Copy any block-specific data when copying to a new block instance.&lt;br /&gt;
&lt;br /&gt;
=== instance_delete() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_delete() {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
Delete everything related to this instance if you have been using persistent storage other than the configdata field.&lt;br /&gt;
&lt;br /&gt;
=== config_print() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function config_print() {&lt;br /&gt;
  // Default behavior: print the config_global.html file&lt;br /&gt;
  // You don&#039;t need to override this if you&#039;re satisfied with the above&lt;br /&gt;
  if (!$this-&amp;gt;has_config()) {&lt;br /&gt;
    return FALSE;&lt;br /&gt;
  }&lt;br /&gt;
  global $CFG, $THEME;&lt;br /&gt;
  &lt;br /&gt;
  print_simple_box_start(&#039;center&#039;, &#039;&#039;, $THEME-&amp;gt;cellheading);&lt;br /&gt;
  include($CFG-&amp;gt;dirroot.&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_global.html&#039;);&lt;br /&gt;
  print_simple_box_end();&lt;br /&gt;
  return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to choose how to display the global configuration screen for your block. This is the screen that the administrator is presented with when he chooses &amp;quot;Settings...&amp;quot; for a specific block. Override it if you need something much more complex than the default implementation allows you to do. However, keep these points in mind:&lt;br /&gt;
&lt;br /&gt;
* If you save your configuration options in $CFG, you will probably need to use global $CFG; before including any HTML configuration screens.&lt;br /&gt;
* The HTML &amp;lt;input&amp;gt; elements that you include in your method&#039;s output will be automatically enclosed in a &amp;lt;form&amp;gt; element. You do not need to worry about where and how that form is submitted; however, you &#039;&#039;&#039;must&#039;&#039;&#039; provide a way to submit it (i.e., an &amp;lt;input type=&amp;quot;submit&amp;quot; /&amp;gt;.&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== config_save() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function config_save($data) {&lt;br /&gt;
  // Default behaviour: save all variables as $CFG properties&lt;br /&gt;
  // You don&#039;t need to override this if you &#039;re satisfied with the above&lt;br /&gt;
  foreach ($data as $name =&amp;gt; $value) {&lt;br /&gt;
    set_config($name, $value);&lt;br /&gt;
  }&lt;br /&gt;
  return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to override the storage mechanism for your global configuration data. The received argument is an associative array, with the keys being setting names and the values being setting values. The default implementation saves everything as Moodle $CFG variables.&lt;br /&gt;
Note that $data does not hold all of the submitted POST data because Moodle adds some hidden fields to the form in order to be able to process it. However, before calling this method it strips the hidden fields from the received data and so when this method is called only the &amp;quot;real&amp;quot; configuration data remain.&lt;br /&gt;
&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== get_content() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function get_content() {&lt;br /&gt;
  // This should be implemented by the derived class.&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should, when called, populate the [[#.24this-.3Econtent| $this-&amp;gt;content]] variable of your block. For details of how to do this, see the [[#.24this-.3Econtent|$this-&amp;gt;content]] section below.&lt;br /&gt;
&lt;br /&gt;
=== has_config() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function has_config() {&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value that denotes whether your block wants to present a configuration interface to site admins or not. The configuration that this interface offers will impact all instances of the block equally.&lt;br /&gt;
To actually implement the configuration interface, you will either need to rely on the default [[#config_print.28.29|config_print()]] method or override it. The full guide contains [[Blocks#The_Effects_of_Globalization|more information on this]].&lt;br /&gt;
&lt;br /&gt;
=== hide_header() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function hide_header() {&lt;br /&gt;
  //Default, false--&amp;gt; the header is shown&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value that denotes whether your block wants to hide its header (or title). Thus, if you override it to return true, your block will not display a title unless the current user is in editing mode.&lt;br /&gt;
&lt;br /&gt;
=== html_attributes() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
  // Default case: an id with the instance and a class with our name in it&lt;br /&gt;
  return array(&#039;id&#039; =&amp;gt; &#039;inst&#039;.$this-&amp;gt;instance-&amp;gt;id, &#039;class&#039; =&amp;gt; &#039;block_&#039;. $this-&amp;gt;name());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return an associative array of HTML attributes that will be given to your block&#039;s container element when Moodle constructs the output HTML. No sanitization will be performed in these elements at all.&lt;br /&gt;
&lt;br /&gt;
If you intend to override this method, you should return the default attributes as well as those you add yourself. The recommended way to do this is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function html_attributes() {&lt;br /&gt;
  $attrs = parent::html_attributes();&lt;br /&gt;
  // Add your own attributes here, e.g.&lt;br /&gt;
  // $attrs[&#039;width&#039;] = &#039;50%&#039;;&lt;br /&gt;
  return $attrs;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== init() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function init() {&lt;br /&gt;
  $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
  $this-&amp;gt;version = 2004111200;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method must be implemented for all blocks. It has to assign meaningful values to the object variables [[#.24this-.3Etitle|$this-&amp;gt;title]] and [[#.24this-.3Eversion|$this-&amp;gt;version]] (which is used by Moodle for performing automatic updates when available).&lt;br /&gt;
&lt;br /&gt;
No return value is expected from this method.&lt;br /&gt;
&lt;br /&gt;
=== instance_allow_config() ===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_allow_config() {&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 through 1.9.&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value. True indicates that your block wants to have per-instance configuration, while false means it does not. If you do want to implement instance configuration, you will need to take some additional steps apart from overriding this method; refer to the full guide for [[Blocks#Configure_That_Out|more information]].&lt;br /&gt;
&lt;br /&gt;
This method&#039;s return value is irrelevant if [[#instance_allow_multiple.28.29|instance_allow_multiple()]] returns true; it is assumed that if you want multiple instances then each instance needs its own configuration.&lt;br /&gt;
&lt;br /&gt;
=== instance_allow_multiple() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_allow_multiple() {&lt;br /&gt;
  // Are you going to allow multiple instances of each block?&lt;br /&gt;
  // If yes, then it is assumed that the block WILL USE per-instance configuration&lt;br /&gt;
  return FALSE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should return a boolean value, indicating whether you want to allow multiple instances of this block in the same page or not. If you do allow multiple instances, it is assumed that you will also be providing per-instance configuration for the block. Thus, you will need to take some additional steps apart from overriding this method; refer to the full guide for [[Blocks#Configure_That_Out|more information]].&lt;br /&gt;
&lt;br /&gt;
=== instance_config_print() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_config_print() {&lt;br /&gt;
  // Default behavior: print the config_instance.html file&lt;br /&gt;
  // You don&#039;t need to override this if you&#039;re satisfied with the above&lt;br /&gt;
  if (!$this-&amp;gt;instance_allow_multiple() &amp;amp;&amp;amp; !$this-&amp;gt;instance_allow_config()) {&lt;br /&gt;
    return FALSE;&lt;br /&gt;
  }&lt;br /&gt;
  global $CFG, $THEME;&lt;br /&gt;
 &lt;br /&gt;
  if (is_file($CFG-&amp;gt;dirroot .&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_instance.html&#039;)) {&lt;br /&gt;
    print_simple_box_start(&#039;center&#039;, &#039;&#039;, $THEME-&amp;gt;cellheading);&lt;br /&gt;
    include($CFG-&amp;gt;dirroot .&#039;/blocks/&#039;. $this-&amp;gt;name() .&#039;/config_instance.html&#039;);&lt;br /&gt;
    print_simple_box_end();&lt;br /&gt;
   } else {&lt;br /&gt;
     notice(get_string(&#039;blockconfigbad&#039;),&lt;br /&gt;
        str_replace(&#039;blockaction=&#039;, &#039;dummy=&#039;, qualified_me()));&lt;br /&gt;
   }&lt;br /&gt;
   return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to choose how to display the instance configuration screen for your block. Override it if you need something much more complex than the default implementation allows you to do. Keep in mind that whatever you do output from [[#instance_config_print.28.29|config_print()]], it will be enclosed in a HTML form automatically. You only need to provide a way to submit that form.&lt;br /&gt;
&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
=== instance_config_save() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_config_save($data) {&lt;br /&gt;
  $data = stripslashes_recursive($data);&lt;br /&gt;
  $this-&amp;gt;config = $data;&lt;br /&gt;
  return set_field(&#039;block_instance&#039;, &#039;configdata&#039;, base64_encode(serialize($data)),&lt;br /&gt;
                      &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method allows you to override the storage mechanism for your instance configuration data. The received argument is an associative array, with the keys being setting names and the values being setting values.&lt;br /&gt;
&lt;br /&gt;
The configuration must be stored in the &amp;quot;configdata&amp;quot; field of your instance record in the database so that Moodle can auto-load it when your block is constructed. However, you may still want to override this method if you need to take some additional action apart from saving the data. In that case, you really should do what data processing you want and then call parent::instance_config_save($data) with your new $data array. This will keep your block from becoming broken if the default implementation of instance_config_save changes in the future.&lt;br /&gt;
&lt;br /&gt;
Note that $data does not hold all of the submitted POST data because Moodle adds some hidden fields to the form in order to be able to process it. However, before calling this method it strips the hidden fields from the received data and so when this method is called only the &amp;quot;real&amp;quot; configuration data remain.&lt;br /&gt;
&lt;br /&gt;
If you want to update the stored copy of the configuration data at run time (for example to persist some changes you made programmatically), you should not use this method. The correct procedure for that purpose is to call [[#instance_config_commit.28.29|instance_config_commit()]].&lt;br /&gt;
&lt;br /&gt;
You should return a boolean value denoting the success or failure of your method&#039;s actions.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
=== preferred_width() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function preferred_width() {&lt;br /&gt;
  // Default case: the block wants to be 180 pixels wide&lt;br /&gt;
  return 180;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 to Moodle 1.9&lt;br /&gt;
&lt;br /&gt;
This method should return an integer value, which is the number of pixels of width your block wants to take up when displayed. Moodle will try to honor your request, but this is actually up to the implementation of the format of the page your block is being displayed in and therefore no guarantee is given. You might get exactly what you want or any other width the format decides to give you, although obviously an effort to accomodate your block will be made.&lt;br /&gt;
&lt;br /&gt;
Most display logic at this point allocates the maximum width requested by the blocks that are going to be displayed, bounding it both downwards and upwards to avoid having a bad-behaving block break the format.&lt;br /&gt;
&lt;br /&gt;
=== refresh_content() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function refresh_content() {&lt;br /&gt;
  // Nothing special here, depends on content()&lt;br /&gt;
  $this-&amp;gt;content = NULL;&lt;br /&gt;
  return $this-&amp;gt;get_content();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method should cause your block to recalculate its content immediately. If you follow the guidelines for [[#get_content.28.29|get_content()]], which say to respect the current content value unless it is NULL, then the default implementation will do the job just fine.&lt;br /&gt;
You should return the new value of [[#.24this-.3Econtent|$this-&amp;gt;content]] after refreshing it.&lt;br /&gt;
&lt;br /&gt;
=== specialization() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function specialization() {&lt;br /&gt;
  // Just to make sure that this method exists.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method is automatically called by the framework immediately after your instance data (which includes the page type and id and all instance configuration data) is loaded from the database. If there is some action that you need to take as soon as this data becomes available and which cannot be taken earlier, you should override this method.&lt;br /&gt;
&lt;br /&gt;
The instance data will be available in the variables [[#.24this-.3Einstance|$this-&amp;gt;instance]] and [[#.24this-.3Econfig|$this-&amp;gt;config]].&lt;br /&gt;
&lt;br /&gt;
This method should not return anything at all.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Methods which you should &#039;&#039;not&#039;&#039; override but may want to use: ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== get_content_type() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function get_content_type() {&lt;br /&gt;
  return $this-&amp;gt;content_type;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the value of [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_title() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function get_title() {&lt;br /&gt;
  return $this-&amp;gt;title;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the value of [[#.24this-.3Etitle|$this-&amp;gt;title]], and is the preferred way of accessing that variable. It is guaranteed to always work, now and forever. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
=== get_version() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;function get_version() {&lt;br /&gt;
  return $this-&amp;gt;version;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the value of [[#.24this-.3Eversion|$this-&amp;gt;version]], and is the preferred way of accessing that variable. Directly accessing the variable is &#039;&#039;&#039;not recommended&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; future library changes may break compatibility with code that does so.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
In previous versions of the documentation, this method was noted as being &amp;quot;guaranteed to always work, now and forever.&amp;quot;  This turned out to not be the case, as [[#.24this-.3Eversion|$this-&amp;gt;version]] is no longer present in Moodle 2.0. Instead, you should use a [[version.php]] file as described on the main blocks documentation page.&lt;br /&gt;
&lt;br /&gt;
=== instance_config_commit() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function instance_config_commit() {&lt;br /&gt;
  return set_field(&#039;block_instance&#039;,&#039;configdata&#039;, base64_encode(serialize($this-&amp;gt;config)), &#039;id&#039;, $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method saves the current contents of [[#.24this-.3Econfig|$this-&amp;gt;config]] to the database. If you need to make a change to the configuration settings of a block instance at run time (and not through the usual avenue of letting the user change it), just make the changes you want to [[#.24this-.3Econfig|$this-&amp;gt;config]] and then call this method.&lt;br /&gt;
&lt;br /&gt;
=== is_empty() ===&lt;br /&gt;
&lt;br /&gt;
For blocks that extend class &#039;&#039;&#039;block_base&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function is_empty() {&lt;br /&gt;
  $this-&amp;gt;get_content();&lt;br /&gt;
  return(empty($this-&amp;gt;content-&amp;gt;text) &amp;amp;&amp;amp; empty($this-&amp;gt;content-&amp;gt;footer));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
For blocks that extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function is_empty() {&lt;br /&gt;
  $this-&amp;gt;get_content();&lt;br /&gt;
  return (empty($this-&amp;gt;content-&amp;gt;items) &amp;amp;&amp;amp; empty($this-&amp;gt;content-&amp;gt;footer));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method returns the a boolean true/false value, depending on whether the block has any content at all to display. Blocks without content are not displayed by the framework.&lt;br /&gt;
&lt;br /&gt;
=== name() ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function name() {&lt;br /&gt;
  static $myname;&lt;br /&gt;
  if ($myname === NULL) {&lt;br /&gt;
    $myname = strtolower(get_class($this));&lt;br /&gt;
    $myname = substr($myname, strpos($myname, &#039;_&#039;) + 1);&lt;br /&gt;
  }&lt;br /&gt;
  return $myname;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Available in Moodle 1.5 and later&lt;br /&gt;
&lt;br /&gt;
This method returns the internal name of your block inside Moodle, without the &#039;&#039;&#039;block_&#039;&#039;&#039; prefix. Obtaining the name of a block object is sometimes useful because it can be used to write code that is agnostic to the actual block&#039;s name (and thus more generic and reusable). For an example of this technique, see the [[#config_print|config_print()]] method.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Methods which you should &#039;&#039;not&#039;&#039; override and &#039;&#039;not&#039;&#039; use at all: ==&lt;br /&gt;
&lt;br /&gt;
=== _add_edit_controls() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _load_instance() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _print_block() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _print_shadow() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
=== _self_test() ===&lt;br /&gt;
This is a private method; no description is given.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;block_base&#039;&#039;&#039; also has a few standard member variables which its methods manipulate. These variables, the purpose of each and the type of data they are expected to hold is explained in the next section of this Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Class variables: ==&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;config ===&lt;br /&gt;
&lt;br /&gt;
This variable holds all the specialized instance configuration data that have been provided for this specific block instance (object). It is an object of type stdClass, with member variables directly corresponding to the HTML &amp;lt;input&amp;gt; elements in the block&#039;s &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;config_instance.html&amp;lt;/span&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
The variable is initialized just after the block object is constructed, immediately before [[#specialization|specialization()]] is called for the object. It is possible that the block has no instance configuration, in which case the variable will be NULL.&lt;br /&gt;
&lt;br /&gt;
It is obvious that there is a direct relationship between this variable and the configdata field in the mdl_block_instance table. However, it is &#039;&#039;strongly&#039;&#039; advised that you refrain from accessing the configdata field yourself. If you absolutely must update its value at any time, it is recommended that you call the method [[#instance_config_commit|instance_config_commit()]] to do the actual work.&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;content ===&lt;br /&gt;
&lt;br /&gt;
This variable holds all the actual content that is displayed inside each block. Valid values for it are either NULL or an object of class stdClass, which must have specific member variables set as explained below. Normally, it begins life with a value of NULL and it becomes fully constructed (i.e., an object) when [[#get_content|get_content()]] is called.&lt;br /&gt;
&lt;br /&gt;
After it is fully constructed, this object is expected to have certain properties, depending on the value of [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]]. &lt;br /&gt;
&lt;br /&gt;
Specifically:&lt;br /&gt;
&lt;br /&gt;
* If [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]] is [[#BLOCK_TYPE_TEXT|BLOCK_TYPE_TEXT]], then [[#.24this-.3Econtent|$this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;text&#039;&#039;&#039; This is a string of arbitrary length and content. It is displayed inside the main area of the block, and can contain HTML.&lt;br /&gt;
# &#039;&#039;&#039;footer&#039;&#039;&#039; This is a string of arbitrary length and contents. It is displayed below the text, using a smaller font size. It can also contain HTML.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* If [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]] is [[#BLOCK_TYPE_LIST|BLOCK_TYPE_LIST]], or if your block derives from &#039;&#039;&#039;block_list&#039;&#039;&#039;, then [[#.24this-.3Econtent|$this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;items&#039;&#039;&#039; This is a numerically indexed array of strings which holds the title for each item in the list that will be displayed in the block&#039;s area. Since usually such lists function like menus, the title for each item is normally a fully qualified HTML &amp;lt;a&amp;gt; tag.&lt;br /&gt;
# &#039;&#039;&#039;icons&#039;&#039;&#039; This is a numerically indexed array of strings which represent the images displayed before each item of the list. It therefore follows that it should have the exact number of elements as the items member variable. Each item in this array should be a fully qualified HTML &amp;lt;img&amp;gt; tag.&lt;br /&gt;
# &#039;&#039;&#039;footer&#039;&#039;&#039; This is a string of arbitrary length and contents. It is displayed below the text, using a smaller font size. It can also contain HTML.&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
* As of Moodle 2.0, if [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]] is [[#BLOCK_TYPE_TREE|BLOCK_TYPE_TREE]], or if your block derives from &#039;&#039;&#039;block_tree&#039;&#039;&#039;, then [[#.24this-.3Econtent|$this-&amp;gt;content]] is expected to have the following member variables:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;items&#039;&#039;&#039; This is an array of &#039;&#039;&#039;tree_item&#039;&#039;&#039; objects, representing the top level of the tree to be displayed. Each tree_item::children property may contain more tree_item objects for the next level down, which in turn contain more tree_item objects, and so on. Note that the tree block type has no footer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you set &#039;&#039;all&#039;&#039; of these variables to their default &amp;quot;empty&amp;quot; values (empty arrays for the arrays and empty strings for the strings), the block will &#039;&#039;&#039;not&#039;&#039;&#039; be displayed at all except to editing users. This is a good way of having your block hide itself to unclutter the screen if there is no reason to have it displayed.&lt;br /&gt;
&lt;br /&gt;
Before starting to populate [[#.24this-.3Econtent|$this-&amp;gt;content]], you should also include a simple caching check. If [[#.24this-.3Econtent|$this-&amp;gt;content]] is exactly equal to NULL then proceed as normally, while if it is not, return the existing value instead of calculating it once more. If you fail to do this, Moodle will suffer a performance hit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;content_type === &lt;br /&gt;
&lt;br /&gt;
This variable instructs Moodle on what type of content it should assume the block has, and is used to differentiate text blocks from list or tree blocks. It is essential that it has a meaningful value, as Moodle depends on this for correctly displaying the block on screen. Consequently, this variable is closely tied with the variable [[#.24this-.3Econtent|$this-&amp;gt;content]]. The variable is expected to have a valid value after the framework calls the [[#init|init()]] method for each block.&lt;br /&gt;
&lt;br /&gt;
Prior to Moodle 2.0, the only valid values for this variable are the two named constants [[#BLOCK_TYPE_TEXT|BLOCK_TYPE_TEXT]] and [[#BLOCK_TYPE_LIST|BLOCK_TYPE_LIST]]. Moodle 2.0 adds a third content type, [[#BLOCK_TYPE_TREE|BLOCK_TYPE_TREE]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
=== $this-&amp;gt;context ===&lt;br /&gt;
&lt;br /&gt;
As of Moodle 2.0, every block now has its own context, and you can always access it via $this-&amp;gt;context. However when checking permissions you need to decide which of two contexts is more appropriate:&lt;br /&gt;
&lt;br /&gt;
# The block context ($this-&amp;gt;context)&lt;br /&gt;
# The page context the block is appearing on ($this-&amp;gt;page-&amp;gt;context). For sticky blocks, this may be a more appropriate choice. &lt;br /&gt;
&lt;br /&gt;
For example, when deciding whether the user can edit the block settings, or see the block, you should use the block context. When deciding whether the user can do something relating to the context where the block appears (can the user see participants here) you should probably use the page context. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
=== $this-&amp;gt;instance === &lt;br /&gt;
&lt;br /&gt;
This member variable holds all the specific information that differentiates one block instance (i.e., the PHP object that embodies it) from another. It is an object of type stdClass retrieved by calling get_record on the table mdl_block_instance. Its member variables, then, directly correspond to the fields of that table. It is initialized immediately after the block object itself is constructed.&lt;br /&gt;
&lt;br /&gt;
This field no longer exists in Moodle 2.0. You should use the [[#.24this-.3Epage|$this-&amp;gt;page]] variable instead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
=== $this-&amp;gt;page ===&lt;br /&gt;
&lt;br /&gt;
As of Moodle 2.0, very block now has access to the page it appears on, via $this-&amp;gt;page. (Therefore, you do not have to use the global $PAGE object in blocks!) &lt;br /&gt;
&lt;br /&gt;
For upgraders, any code that previously relied on $this-&amp;gt;instance-&amp;gt;... will probably break. Information about the page the block is appearing on is available from $this-&amp;gt;page-&amp;gt;.... Specifically:&lt;br /&gt;
* $this-&amp;gt;instance-&amp;gt;pagetype should be changed to $this-&amp;gt;page-&amp;gt;pagetype&lt;br /&gt;
* $this-&amp;gt;instance-&amp;gt;pageid - there is no longer a concept of page id. Instead, you are probably looking for $this-&amp;gt;page-&amp;gt;course, $this-&amp;gt;page-&amp;gt;cm or $this-&amp;gt;page-&amp;gt;activityrecord.&lt;br /&gt;
&lt;br /&gt;
=== $this-&amp;gt;title === &lt;br /&gt;
&lt;br /&gt;
This variable is a string that contains the human-readable name of the block. It is used to refer to blocks of that type throughout Moodle, for example in the administrator&#039;s block configuration screen and in the editing teacher&#039;s add block menu. It is also the title that is printed when the block is displayed on screen, although blocks can specifically change this title to something else if they wish (see below). The variable is expected to have a valid value after the framework calls the [[#init|init()]] method for each object.&lt;br /&gt;
&lt;br /&gt;
In the case of blocks which may want to configure their title dynamically through instance configuration, it is still essential to provide a valid title inside [[#init|init()]]. This title may then be overridden when the [[#specialization|specialization()]] method is called by the framework:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function specialization() {&lt;br /&gt;
  // At this point, $this-&amp;gt;instance and $this-&amp;gt;config are available&lt;br /&gt;
  // for use. We can now change the title to whatever we want.&lt;br /&gt;
  $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;variable_holding_the_title;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A lot of blocks seem to use &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $this-&amp;gt;title = get_string(&#039;blockname&#039;, ... );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to set the title of the block (and then put a more specific title inside the language file).&lt;br /&gt;
&lt;br /&gt;
If there is no proper language string, the title of the block will then be set to &#039;&#039;blockname&#039;&#039;. If there is another block with the same generic title, then an error will show up: Naming conflict.&lt;br /&gt;
&lt;br /&gt;
To avoid this error on installations with missing language strings, use a more specific name when calling the language string...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, ... );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That way all blocks will show up with a unique title in the admin area, even if people have not yet succeeded in placing language files in the correct location&lt;br /&gt;
&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
=== $this-&amp;gt;version === &lt;br /&gt;
&lt;br /&gt;
This variable should hold each block&#039;s version number in the form &#039;&#039;&#039;YYYYMMDDXX&#039;&#039;&#039;, as per the convention throughout Moodle. The version number is used by Moodle to detect when a block has been upgraded and it consequently needs to run the block&#039;s upgrade code to bring the &amp;quot;old&amp;quot; version of the block&#039;s data up to date. The variable is expected to have a valid value after the framework calls the [[#init|init()]] method for each block.&lt;br /&gt;
&lt;br /&gt;
Most blocks do not keep complex data of their own in the database the way that modules do, so in most cases nothing actually happens during a block version upgrade. However, the version number is displayed in the administration interface for blocks. It is good practice therefore to change your block&#039;s version number when it gains new functionality or receives important bug fixes, to enable site administrators to easily identify the exact version of the block they are working with.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
$this-&amp;gt;version is no longer present in Moodle 2.0. Instead, you should use a version.php file as described on the main blocks documentation page.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Named constants: ==&lt;br /&gt;
&lt;br /&gt;
Appearing throughout the code related to the Blocks API, there are a number of predefined constants that are utilized to avoid the use of &amp;quot;magic numbers&amp;quot; in the code. These constants are:&lt;br /&gt;
&lt;br /&gt;
=== BLOCK_TYPE_LIST ===&lt;br /&gt;
&lt;br /&gt;
This is one of the valid values for the [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[#.24this-.3Econtent|$this-&amp;gt;content]].&lt;br /&gt;
&lt;br /&gt;
=== BLOCK_TYPE_TEXT ===&lt;br /&gt;
This is one of the valid values for the [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[#.24this-.3Econtent|$this-&amp;gt;content]].&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
=== BLOCK_TYPE_TREE ===&lt;br /&gt;
&lt;br /&gt;
Introduced in Moodle 2.0, this is one of the valid values for the [[#.24this-.3Econtent_type|$this-&amp;gt;content_type]] member variable of every block. Its value specifies the exact requirements that Moodle will then have for [[#.24this-.3Econtent|$this-&amp;gt;content]].&lt;br /&gt;
&lt;br /&gt;
== Extended block types ==&lt;br /&gt;
&lt;br /&gt;
Several additional classes are defined in the block library that extend block_base. These are basically shorthand ways of creating blocks with list or tree content types, rather than instantiating a block_base object and setting values on it. The &#039;&#039;&#039;block_list&#039;&#039;&#039; class can be used to create list-based blocks as described above, and as of Moodle 2.0, the &#039;&#039;&#039;block_tree&#039;&#039;&#039; class will allow you to create tree-structured blocks easily. If you are using one of these blocks, you will not need to set $this-&amp;gt;content_type as described above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Blocks]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
&lt;br /&gt;
[[es:Desarrollo de bloques]]&lt;br /&gt;
[[ja:開発:ブロック/付録A]]&lt;br /&gt;
[[ru:Blocks/Appendix_A]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=BioAuth_Plugin&amp;diff=64541</id>
		<title>BioAuth Plugin</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=BioAuth_Plugin&amp;diff=64541"/>
		<updated>2025-02-10T07:48:41Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Work_in_progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = BioAuth: A Moodle plugin for determining Quiz authorship&lt;br /&gt;
|state = Community bonding period&lt;br /&gt;
|tracker = CONTRIB-4337&lt;br /&gt;
|discussion = XXX&lt;br /&gt;
|assignee = [https://moodle.org/user/profile.php?id=1595676 Vinnie Monaco]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;GSOC&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt; &#039;13&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The purpose of the BioAuth plugin is to provide a mechanism for verifying a user&#039;s identity based on behavioral biometrics. This is accomplished by capturing keystrokes from a user and matching it against a known template for that user. The initial release of BioAuth will only support biometric authentication for essay-type questions on quizzes. Other sources of keystrokes may be added in future releases.&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
&lt;br /&gt;
First, install the BioAuth local plugin. This contains everything needed to authenticate students but is not able to collect any data. Then install the quiz access rule BioLogger plugin. This allows keystroke timing information to be captured on client computers during quiz attempts.&lt;br /&gt;
&lt;br /&gt;
===Requirements===&lt;br /&gt;
&lt;br /&gt;
The BioAuth plugin requires a Moodle installation with a MySQL backend and java (&amp;gt;1.5) installed on the server.&lt;br /&gt;
&lt;br /&gt;
===Instructions===&lt;br /&gt;
&lt;br /&gt;
TODO: local_bioauth installation instructions&lt;br /&gt;
&lt;br /&gt;
TODO: quiz_accessrule installation instructions&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
The BioAuth and BioLogger plugins must both be installed for the BioAuth plugin to work properly. &lt;br /&gt;
&lt;br /&gt;
Once the plugin is installed, it can be enabled for existing courses through the report page. It will automatically be enabled for newly created courses.&lt;br /&gt;
&lt;br /&gt;
Important: The course must contain at least one quiz with one essay question. The plugin can only log keystrokes from essay questions which use the rich html editor.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
The raw data is processed in several stages in order to make an authentication decision, and either confirm or deny the identity of an individual:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Feature extraction → Fallback Procedure → Outlier Removal → Normalization → Classification&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;session&#039;&#039;&#039; is the duration in which some data is continuously captured from a user. This could be a quiz or some activity on a forum. A user may have multiple sessions capture while they are logged in. Sessions should capture data from an independent activity or task which lasts anywhere from roughly 10 to 60 minutes depending on the task involved.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;keystroke event&#039;&#039;&#039; is the atomic event captured by the hardware keyboard of a desktop or laptop computer. It consists of a press time, release time, and key identity. The key is identified by it&#039;s location on the keyboard, not the ASCII code of the letter which was actually printed on screen. For example, &#039;A&#039; is the same as &#039;a,&#039; even though they have different ASCII codes, and left shift is not the same as right shift, even though they have the same ASCII codes. The identity of the key can usually be determined by the key code, which should be unique for every key on the keyboard. Care must be taken to correlate key codes across different browsers and operating systems, as they may be platform dependent. For more information on events and keycodes, see [http://www.quirksmode.org/js/keys.html Quirksmode on JavaScript keys].&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;stylometry event&#039;&#039;&#039; is a portion of text that was emitted to the screen in a continuous manner. Stylometry events are separated by a change in focus or cursor position. Events that segment consecutive stylometry events (ending the current stylometry event and beginning a new one) include:&lt;br /&gt;
&lt;br /&gt;
* Changing the window focus&lt;br /&gt;
* Clicking on a different area of text in the current entry&lt;br /&gt;
* Using the arrow keys to navigate a text area&lt;br /&gt;
* Moving to a different text area. &lt;br /&gt;
&lt;br /&gt;
Using the delete key to modify text which was already printed on screen does not end the current stylometry event, although it does modify the text which is contained in the current stylometry event. Upon completion of a subtask, the sequence of stylometry events will roughly consist of the final text that the user actually typed and appeared on screen.&lt;br /&gt;
&lt;br /&gt;
===Feature Extraction===&lt;br /&gt;
&lt;br /&gt;
A &amp;quot;keystroke feature&amp;quot; is a measurement made on the time differences between the press and release events of keystrokes. The most commonly used keystroke features are means and standard deviations of key duration and transition times.&lt;br /&gt;
&lt;br /&gt;
During feature extraction, the raw data (keystroke, stylometry) is mapped to a feature space. Features usually consist of measurements on some distribution in the raw data. The hold time is the duration a key is held, or press time – release time. There are several types of transition times, the most common being release-press and press-press latencies. For example, take two consecutive keystrokes, [A,B]. The hold time of A would be (A_release - A_press)&lt;br /&gt;
and the transition times, (B_press – A_release), (B_press – A_press). &lt;br /&gt;
&lt;br /&gt;
The hold times of A form a distribution from which the mean and standard deviation may be taken. Similarly for the transition times between A and B, assuming that the sequence [A,B] occurs with a high enough frequency in the sample provided. For missing data, a fallback procedure is used, described in the next section.&lt;br /&gt;
&lt;br /&gt;
===Fallback Procedure===&lt;br /&gt;
&lt;br /&gt;
Dealing with arbitrary can lead to missing observations. To compensate for this, a fallback procedure is used to compensate for missing data. Missing features may be computed from observations which are known to be correlated with the missing data.&lt;br /&gt;
&lt;br /&gt;
It is known that the timing information for closely grouped keys correlate well enough to used them in an instance of missing data. For this reason, a fallback hierarchy based on the physiology of the touch-typist is used.&lt;br /&gt;
&lt;br /&gt;
===Outlier Removal===&lt;br /&gt;
&lt;br /&gt;
Due to inconsistencies in the data provided, outliers must be removed. It is common for a user to take a break while typing, creating a large transition time between keystrokes. These can easily be removed by excluding observations which fall outside the mean observation, usually +/- 2 standard deviations.&lt;br /&gt;
&lt;br /&gt;
===Normalization===&lt;br /&gt;
&lt;br /&gt;
Features are normalized so that each feature is weighted equally in the KNN classification. The normalization clamps each feature between 0 and 1.&lt;br /&gt;
&lt;br /&gt;
===Classification===&lt;br /&gt;
&lt;br /&gt;
The feature space is first transformed into a feature difference space by taking the differences between every combination of feature vectors. The differences make up two classes: differences within a user and differences between users. The unknown sample (query) is compared to the feature vectors of it&#039;s claimed identity. Differences between the query vector and the user&#039;s template are taken. These differences are then classified as either within user or between user by comparing them to the vectors that make up the difference space. A KNN algorithm is used to classify the unknown sample by looking at the closest neighbors, which came from either the same user or different users.&lt;br /&gt;
&lt;br /&gt;
==Settings==&lt;br /&gt;
&lt;br /&gt;
===Mode===&lt;br /&gt;
&lt;br /&gt;
Currently, the plugin can either be Enabled or Disabled. Setting the mode to Enabled will activate biometric authentication for any new courses which are created. The plugin can be enabled for existing courses through the overview report page.&lt;br /&gt;
&lt;br /&gt;
===Weeks keep active===&lt;br /&gt;
&lt;br /&gt;
The number of weeks to keep a course active, after the plugin has been enabled. During this time, the plugin will continuously look for new data and re-authenticate students. The results are updated as new data is collected.&lt;br /&gt;
&lt;br /&gt;
===Min keystrokes per quiz===&lt;br /&gt;
&lt;br /&gt;
The desired number of keystrokes per quiz. This setting will only affect the time at which the plugin has determined enough data has been collected to begin authenticating students. See Percent data needed.&lt;br /&gt;
&lt;br /&gt;
===Percent data needed===&lt;br /&gt;
&lt;br /&gt;
How much data is needed before authentications should begin to take place. This only affects the initial results, which are continuously updated as new data is collected. The default setting is 50%, which would be 50% of the total data needed (students X quizzes X keystrokes-per-quiz)&lt;br /&gt;
&lt;br /&gt;
===Max concurrent jobs===&lt;br /&gt;
&lt;br /&gt;
The number of jobs which may be run simultaneously during a cron job.&lt;br /&gt;
&lt;br /&gt;
===Cache key codes===&lt;br /&gt;
&lt;br /&gt;
Use cache for looking up the keycodes when enrolling new data. This works very similarly to the language cache used in the string api.&lt;br /&gt;
&lt;br /&gt;
===Knn===&lt;br /&gt;
&lt;br /&gt;
The model parameter K, where K is the number of neighbors to use when making an authentication decision.&lt;br /&gt;
&lt;br /&gt;
===Min key frequency===&lt;br /&gt;
&lt;br /&gt;
The minimum number of keystroke occurrences before a fallback procedure is used. The fallback procedure is defined in the features file.&lt;br /&gt;
&lt;br /&gt;
===Decision mode===&lt;br /&gt;
&lt;br /&gt;
How the classifier should behave when making an authentication decision. In reality, there will always be at least a small error in the accuracy of the classifier. This setting will determine whether a false acceptance or false rejection should be weighted more heavily. A more secure system would reduce the number of false acceptances at the cost of increasing the number of false rejections. The tradeoff can be seen on the ROC curve in the quiz report.&lt;br /&gt;
&lt;br /&gt;
===Feature set===&lt;br /&gt;
&lt;br /&gt;
Which feature set to use. The features are defined in the feature files and loaded during installation.&lt;br /&gt;
&lt;br /&gt;
==Report==&lt;br /&gt;
&lt;br /&gt;
===Overview===&lt;br /&gt;
&lt;br /&gt;
The overview report gives a summary of each course. The plugin can be enabled or disabled for any particular course by clicking the appropriate action button.&lt;br /&gt;
&lt;br /&gt;
===Quiz===&lt;br /&gt;
&lt;br /&gt;
The quiz report displays the authentication results for every student in the course. In each cell, a student can either be authenticated or rejected. A &#039;-&#039; will appear in cells where enough data has not been collected to make a decision.&lt;br /&gt;
&lt;br /&gt;
The graph at the top of the page displays the tradeoff between the false acceptance and false rejection rate. This is the receiver operating characteristic (ROC) curve. It can be used to determine the overall performance of the classifier for the given population of students.&lt;br /&gt;
&lt;br /&gt;
==Multi-language support==&lt;br /&gt;
The BioAuth plugin was designed to be easily extensible to other languages and locales. This can be done by defining the physical keys which may be pressed on the keyboard and creating the keystroke features. Defining the keys themselves is straightforward and only requires a mapping of the different agent/locale key codes to the name of the key. Creating the keystroke features requires some knowledge of the target language and application in order to create features which may easily identify an individual. Usually, keys which occur with a high frequency are good to use as features as are transitions between commonly-occuring keys.&lt;br /&gt;
&lt;br /&gt;
===Keys===&lt;br /&gt;
&lt;br /&gt;
Keycodes for various languages are defined in the keys/[language]/keycode.php file. The system will detect the current language and use the appropriate keycode file to translate the keycodes. This is needed because the keycodes vary across different browser agents and platforms. The different codes must all be mapped to the physical key that they were generated by.&lt;br /&gt;
&lt;br /&gt;
===Features===&lt;br /&gt;
&lt;br /&gt;
Features are defined in the features/ folder. Feature sets are not tied to any particular language because the same feature set may be used for multiple languages or there may be several feature sets for one language. The installation comes with a feature set designed for standard QWERTY keyboards and uses a touch-type hierarchy fallback procedure.&lt;br /&gt;
&lt;br /&gt;
==Schedule==&lt;br /&gt;
&lt;br /&gt;
The work will be completed under the following schedule:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Dates&lt;br /&gt;
! Task&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| May 27 - June 17&lt;br /&gt;
| Draft of design, to be accomplished during Community Bonding Period.&lt;br /&gt;
Also, deadline for submitting a paper to MRC2013.&lt;br /&gt;
| Complete&lt;br /&gt;
|-&lt;br /&gt;
| June 17 - July 1&lt;br /&gt;
| Binary classifier and authentication decision functions&lt;br /&gt;
| Complete&lt;br /&gt;
|-&lt;br /&gt;
| July 1 - July 15&lt;br /&gt;
| Key logger&lt;br /&gt;
DB model&lt;br /&gt;
| Complete&lt;br /&gt;
|-&lt;br /&gt;
| July 15 - August 1&lt;br /&gt;
| Keystroke Feature extractor&lt;br /&gt;
| Complete&lt;br /&gt;
|-&lt;br /&gt;
| August 1 -August 11&lt;br /&gt;
| UI for results and settings&lt;br /&gt;
| Complete&lt;br /&gt;
|-&lt;br /&gt;
| August 15- Sept. 1&lt;br /&gt;
| Beta testing with trusted volunteers.&lt;br /&gt;
Bug fixes and final report.&lt;br /&gt;
| Complete&lt;br /&gt;
|-&lt;br /&gt;
| Sept. 1 - Sept. 23&lt;br /&gt;
| Prepare for release.&lt;br /&gt;
Scrub code, tests, documentation.&lt;br /&gt;
Live testing during Fall 2013 academic semester&lt;br /&gt;
| Complete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[GSOC/2013|Moodle GSoC projects for 2013]]&lt;br /&gt;
* [[GSOC|Moodle GSoC Overview page]]&lt;br /&gt;
&lt;br /&gt;
[[Category:GSOC]]&lt;br /&gt;
[[Category:Project]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Better_handling_of_overdue_quiz_attempts&amp;diff=64540</id>
		<title>Better handling of overdue quiz attempts</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Better_handling_of_overdue_quiz_attempts&amp;diff=64540"/>
		<updated>2025-02-10T07:48:17Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Handling of overdue quiz attempts&lt;br /&gt;
|state = Implementation complete. Testing.&lt;br /&gt;
|tracker = MDL-3030, MDL-4309&lt;br /&gt;
|discussion = [http://moodle.org/mod/forum/discuss.php?d=201355 Quiz forum thread about testing] [http://moodle.org/mod/forum/discuss.php?d=188534 Old Quiz forum thread about the proposal]&lt;br /&gt;
|assignee = [[User:Tim Hunt|Tim Hunt]]&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
There is a tricky issue to do with what happens exactly when time runs on on a quiz. On the one hand, we want to let students use every second of time. On the other hand, the end of a quiz is often a time of high server load, and so Moodle is likely to responding slowly. Therefore, we have to prevent students from cheating on the time-limit while still processing their last-minute submission even if the server is heavily loaded.&lt;br /&gt;
&lt;br /&gt;
There is also the problem of what happens if the student just logs out and does not submit at all. At the moment the attempt goes into a sort of limbo where Moodle can&#039;t really do anything with it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What happens at the moment==&lt;br /&gt;
&lt;br /&gt;
Currently there are only really two states a quiz attempt can be in, and they are distinguished by whether quiz_attempts.timefinish is 0 or contains a time-stamp.&lt;br /&gt;
&lt;br /&gt;
[[Image:Quiz_attempt_states_now.png]]&lt;br /&gt;
&lt;br /&gt;
At most one attempt is allowed to be in the &#039;&#039;&#039;In progress&#039;&#039;&#039; state at any time.&lt;br /&gt;
&lt;br /&gt;
After time expires, (either because the time limit runs out, or the close date passes) the attempt is in a weird state. Well, not really, the attempt is still considered to be &#039;&#039;&#039;In progress&#039;&#039;&#039;, but the student is no longer allowed to access it, so there is no way to get at the &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; button to submit it. Also, if the quiz allows more than one attempt, the student cannot start a new attempt, because they already have an &#039;&#039;&#039;In progress&#039;&#039;&#039; attempt (which they are not allowed to access!)&lt;br /&gt;
&lt;br /&gt;
The known work-around is, as teacher, to:&lt;br /&gt;
# edit quiz settings to allow more time;&lt;br /&gt;
# login-as the student and submit the quiz;&lt;br /&gt;
# set the time-limit or close data back to what it should be.&lt;br /&gt;
This is a real pain.&lt;br /&gt;
&lt;br /&gt;
Before reading on, you may wish to remind yourself of the [[Quiz user interface overview]], so you know what the key scripts view/startattempt/attempt/processattempt/summar/review.php each do.&lt;br /&gt;
&lt;br /&gt;
To document the two existing transitions in some detail (note, all transitions are logged, I have not bothered to say that every time):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Start attempt===&lt;br /&gt;
&lt;br /&gt;
Goes to: In progress&lt;br /&gt;
&lt;br /&gt;
Allowed when: If the student does not currently have any &#039;&#039;&#039;In progress&#039;&#039;&#039; attempt, and if they meet all the conditions imposed by the [[Quiz access rules|access rules]], they may start one.&lt;br /&gt;
&lt;br /&gt;
How it is done: The student clicks the &#039;&#039;&#039;Start attempt&#039;&#039;&#039; button on view.php. Technically, this takes the form of a POST request to startattempt.php.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# The attempt, and corresponding $quba, are created.&lt;br /&gt;
# They are initialised by adding all the questions, which may depend on randomisation, and &#039;each attempt builds on last&#039;.&lt;br /&gt;
# The attempt and all associated data is written to the database.&lt;br /&gt;
# A quiz_attempt_started event is raised. (This even it not used in standard Moodle.)&lt;br /&gt;
&lt;br /&gt;
===Transition: Submit all and finish===&lt;br /&gt;
&lt;br /&gt;
Goes from: In progress&lt;br /&gt;
&lt;br /&gt;
Goes to: Finished&lt;br /&gt;
&lt;br /&gt;
Allowed when: The student has an &#039;&#039;&#039;In progress&#039;&#039;&#039; attempt, which they are currently allowed to access according to the access rules. In particular, where the time limit has not run out, and the close date has not passed.&lt;br /&gt;
&lt;br /&gt;
How it is done: Either&lt;br /&gt;
* The student clicks the &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; button on summary.php; or&lt;br /&gt;
* Time runs out while the student is working on the quiz, and so the quiz is submitted automatically (if JavaScript is enabled).&lt;br /&gt;
Technically, this takes the form of a POST request to processattempt.php, althought the code that does the work is the quiz_attempt::process_attempt method in attemptlib.php.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# All questions that are not already finishes are finished.&lt;br /&gt;
# The updated question states are written to the database.&lt;br /&gt;
# The quiz_attempt record is updated with the timefinish and the total mark.&lt;br /&gt;
# The overall quiz grade (combining all the student&#039;s attempt scores) is updated, and stored in the gradebook.&lt;br /&gt;
# A quiz_attempt_submitted event is raised. (This is used by the quiz itself to send out any tutor or student notification messages that are enabled.)&lt;br /&gt;
&lt;br /&gt;
==Rough outline of the solution==&lt;br /&gt;
&lt;br /&gt;
We will introduce a new quiz settings &#039;&#039;&#039;When time expires&#039;&#039;&#039; and &#039;&#039;&#039;Grace period&#039;&#039;&#039;. When time expires is the strategy we will use for overdue attempts. For some strategies, they will need an amount of extra time that is the grace period. The possible strategies are:&lt;br /&gt;
&lt;br /&gt;
# Submit attempt automatically,&lt;br /&gt;
# Allow a grace period to submit, but not change any responses, or&lt;br /&gt;
# That&#039;s it. Tough luck! - &#039;&#039;we need a better name for this!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. Corresponds to doing an automatic submit all and finish. 3. Corresponds to automatically moving the attempt to the &#039;&#039;&#039;Abandoned state&#039;&#039;&#039;. See below. 2. is more interesting (and is what the OU wants for assessed tests).&lt;br /&gt;
&lt;br /&gt;
If the student has not submitted their attempt when time runs out, then the attempt moves into the &#039;&#039;&#039;Overdue&#039;&#039;&#039; state. In this state, when the student tries to get to the quiz attempt, then can only go to the Summary page, where all they can do is to click the &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
If they finish submitted before the grace period runs out, then their attempt is counted.&lt;br /&gt;
&lt;br /&gt;
If the student still does not submit, then the attempt moves into the &#039;&#039;&#039;Abandoned&#039;&#039;&#039; state. This means that the student is not prevented from starting a new attempt, if the quiz allows it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Question: should we allow the student to abandon the current attempt at any time? For example, if an interactive quiz allows multiple attempts, and the student has got off to a bad start, should we let them abandon and start again, or should we force them to &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; if they want a new attempt? - for now we will not allow students to abandon any attempt.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In addition, we will start storing the quiz_attempt.state explicitly in the database, rather than relying on deducing it from timefinish or other columns. In a sense this is redundant information, but since significant things happen when the state changes (e.g. a message might be sent) I think making the state, and hence the state transition, explicit, will make the code clearer.&lt;br /&gt;
&lt;br /&gt;
We will need code that detects when an attempt is in the &#039;wrong&#039; state. For example, if a state is stored in the database as &#039;&#039;&#039;In progress&#039;&#039;&#039;, but time has now expired, then we will need to detect that and correct it by triggering the correct state transition. I think we need to do this in two ways:&lt;br /&gt;
# Whenever we load an attempt from the database. This ensure that if the user is actively working on the quiz when a state transition is supposed to happen, they will immediately see the attempt change state.&lt;br /&gt;
# We will need to add a cron script that detects attempts becoming overdue when no-one is looking at them.&lt;br /&gt;
(Note there is a subtlety, the JavaScript timer that runs in the user&#039;s browser will try to automatically trigger a submit, they may be happening at the same time as a teacher is reviewing the attempt (which might trigger 1) and cron may also be running at the same time (which might trigger 2). Therefore, we need a clear protocol to avoid nasty race-conditions.&lt;br /&gt;
&lt;br /&gt;
Actually, a possible third way (instead of, or in addition to cron). Perhaps we should detect this when the quiz settings (or overrides) are edited, and check all attempts then and trigger state transitions. This might be a performance problem on quizzes with thousands of attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New state diagram==&lt;br /&gt;
&lt;br /&gt;
[[Image:Quiz_attempt_states.png]]&lt;br /&gt;
&lt;br /&gt;
At most one attempt can be in either the &#039;&#039;&#039;In progress&#039;&#039;&#039; or &#039;&#039;&#039;Overdue&#039;&#039;&#039; states at any time.&lt;br /&gt;
&lt;br /&gt;
The existing transitions need to be updated:&lt;br /&gt;
* They all need to set the new quiz_attempt.state column as part of What happens.&lt;br /&gt;
* The transition Submit all and finish can now also go from &#039;&#039;&#039;Overdue&#039;&#039;&#039; to &#039;&#039;&#039;Finished&#039;&#039;&#039;.&lt;br /&gt;
* When time runs out as a student is working on their quiz attempt, this should no longer trigger an automatic Submit all and finish. Instead it should trigger an automatic Time expires.&lt;br /&gt;
&lt;br /&gt;
The new transitions are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Time expires===&lt;br /&gt;
&lt;br /&gt;
Goes from: In progress&lt;br /&gt;
&lt;br /&gt;
Goes to: Overdue&lt;br /&gt;
&lt;br /&gt;
Allowed when: Time expires, either due to the time-limit, the close date, or some other custom access rule; or because the teacher has edited the time limit and/or close date and shortened them; and when the overdue strategy is &amp;quot;Allow a grace period to submit, but not change any responses&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
How it is done: Detected automatically by the Moodle code, either because&lt;br /&gt;
* time has passed;&lt;br /&gt;
* the teacher has edited the quiz settings or overrides to shorten the time limit and/or close date; or&lt;br /&gt;
* triggered by the countdown timer JavaScript, in which case this will trigger a POST to processattempt.php.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# quiz_attempt.state is updated&lt;br /&gt;
# quiz_attempt_overdue event is raised. (The quiz will use this itself to send a warning message to the student, if that is enabled.)&lt;br /&gt;
# If the student is currently working on the quiz, they are redirected to the summary.php page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Give up===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;(not sure that is the best name)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Goes from: Overdue / In progress&lt;br /&gt;
&lt;br /&gt;
Goes to: Abandoned&lt;br /&gt;
&lt;br /&gt;
Allowed when: Time expires, and the overdue strategy is &amp;quot;That&#039;s it. Tough luck!&amp;quot;; or the grace period expires when an attempt is in the &#039;&#039;&#039;Overdue&#039;&#039;&#039; state.&lt;br /&gt;
&lt;br /&gt;
How it is done: Detected automatically by the Moodle code, either because&lt;br /&gt;
* time has passed;&lt;br /&gt;
* the teacher has edited the quiz settings or overrides to shorten the time limit, close date and/or grace period; or&lt;br /&gt;
* triggered by the countdown timer JavaScript, in which case this will trigger a POST to processattempt.php; or&lt;br /&gt;
* if we decide to allow it, the student clicks a &#039;Give up button&#039;, perhaps on the summary page.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# quiz_attempt.state is updated&lt;br /&gt;
# quiz_attempt_abandoned event is raised. (For completeness. I don&#039;t foresee a use for this at the moment.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Time limit extended===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This shows the kind of tricky thing that can happen. We have to consider what happens if the teacher edits the quiz settings to extend the time limit when an attempt has already been marked overdue.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Goes from: Overdue&lt;br /&gt;
&lt;br /&gt;
Goes to: In progress&lt;br /&gt;
&lt;br /&gt;
Allowed when: The teacher edits the quiz settings or the overrides and extends the time limit.&lt;br /&gt;
&lt;br /&gt;
How it is done: Detected automatically by the Moodle code.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# quiz_attempt.state is updated&lt;br /&gt;
# quiz_attempt_restarted event is raised. (For completeness. I don&#039;t foresee a use for this at the moment.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What can be accessed when==&lt;br /&gt;
&lt;br /&gt;
For an &#039;&#039;&#039;In progress&#039;&#039;&#039;&#039; attempt: The student can access attempt.php and summary.php; the teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
For an &#039;&#039;&#039;Overdue&#039;&#039;&#039;&#039; attempt: The student can access review.php and summary.php; the teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
For a &#039;&#039;&#039;Finished&#039;&#039;&#039;&#039; attempt: The student and teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
For an &#039;&#039;&#039;Abandoned&#039;&#039;&#039;&#039; attempt: The student and teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Summary of changes==&lt;br /&gt;
&lt;br /&gt;
===Database changes===&lt;br /&gt;
&lt;br /&gt;
* New column quiz.overduehandling (char) to store which strategy we will use for overdue attempts.&lt;br /&gt;
* New column quiz.graceperiod (int) to store the time an attempt is allowed to remain in the &#039;&#039;&#039;Overdue&#039;&#039;&#039; state.&lt;br /&gt;
* New column quiz_attempt.state (char) to explicitly store the attempt state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New capability===&lt;br /&gt;
&lt;br /&gt;
* mod/quiz:emailwarnoverdue to control overdue warning messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===UI changes===&lt;br /&gt;
&lt;br /&gt;
* New fields &#039;When time expires&#039; and &#039;Grace period&#039; on the quiz settings form, with corresponding admin settings.&lt;br /&gt;
* Do we need even more columns of &#039;review options&#039; on the quiz settings form? (For example for &#039;&#039;&#039;Overdue&#039;&#039;&#039; and &#039;&#039;&#039;Abandoned&#039;&#039;&#039; attempts.) Perhaps it is time to move these settings to a separate page?&lt;br /&gt;
* Information about the grace period may need to be displayed on the quiz settings page, or on the summary page for overdue attempts.&lt;br /&gt;
* List of attempts on the view.php page needs to indicate the state of attempts.&lt;br /&gt;
* review.php page needs to indicate the attempt state.&lt;br /&gt;
* Display attempt state in the quiz reports where appropriate.&lt;br /&gt;
&lt;br /&gt;
==Rough work break-down==&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; New quiz.overduehandling, quiz.graceperiod and quiz_attempt.state DB columns definition, upgrade code, backup &amp;amp; restore.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Overdue handling and Grace period setting on quiz form, with any validation. Verify create / edit works.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Implement back end of the three new transitions.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Code where attempts are loaded to identify attempts in the wrong state and trigger a transition if necessary.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Catch the quiz_attempt_overdue event and send an email.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Make attempt_state clear on the view page list of past attempts.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Update logic for the &#039;Start attempt button&#039;, and in startattempt.php so that for overdue attempts users are redirected to the summary page.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Update summary page to display appropriate information about overdue attempts.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Update processattempts.php so that it correctly handles one single submission after an attempt becomes overdue, and, for overdue attempts, will only redirect to the summary page.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Display the attempt state on the review page.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Add the attempt state to the overview and responses quiz reports (this will actually be a change in the base class).&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Add new options to the attempt and overview reports to filter the report by attempt state. (We can probably usefully refactor the settings forms and preferences handling to extract a base class.)&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Out of scope&amp;lt;/span&amp;gt; While we are working here, we should really update these two reports to use the Moodle 2.x enrolment SQL, instead of get_users_by_capability.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Change the statistics report to analyse attempts with state = finished, rather than timefinish &amp;lt;&amp;gt; 0.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Cron to detect attempts in the wrong state and trigger state transitions.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Review all remaining occurrences of -&amp;gt;timefinish in the quiz code.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Check the quiz results block - no changes required.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Out of scope&amp;lt;/span&amp;gt; - the official work-around is: &amp;quot;Don&#039;t do that&amp;quot;, at least for now - Deal with what happens when the teacher edits the quiz settings - which might change the times or the policies. Work out what to update.&lt;br /&gt;
&lt;br /&gt;
== Test script==&lt;br /&gt;
&lt;br /&gt;
The 3 examples at http://moodle.org/mod/forum/discuss.php?d=188534 are a good starting point. They just need to be elaborated.&lt;br /&gt;
&lt;br /&gt;
==Hypothetical other transitions==&lt;br /&gt;
&lt;br /&gt;
The following state-transitions can also be conceived, and could be implemented in the future, but they are out-of-scope for this proposal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Reopen attempt===&lt;br /&gt;
&lt;br /&gt;
Goes from: Finished / Abandoned&lt;br /&gt;
&lt;br /&gt;
Goes to: In progress&lt;br /&gt;
&lt;br /&gt;
Allowed when: Time has not expired, and the current user has the appropriate capability.&lt;br /&gt;
&lt;br /&gt;
(For example, the student accidentally clicked Submit all and finish, and the teacher wants to be nice and undo that for them. Alternatively an attempt has become Abandoned because time ran out, but then the teacher extended the grace period or time limit, and so wants to re-open some attempts. In this case, the transition may go to &#039;&#039;&#039;Overdue&#039;&#039;&#039;, or perhaps that is a different transition, or perhaps the right way to handle that is to first transition to &#039;&#039;&#039;In progress&#039;&#039;&#039; and then transition to &#039;&#039;&#039;Overdue&#039;&#039;&#039;. I think it is clear why this is being considered out-of-scope.)&lt;br /&gt;
&lt;br /&gt;
How it is done: Probably clicking a button on the review page or in the quiz reports. This would probably be a POST to a new reopenattempt.php&lt;br /&gt;
&lt;br /&gt;
What happens: This is a bit tricky because lots of complex stuff happens on Submit all and finish that now needs to be undone, but I think a possible approach is to delete any question_attempts_steps added by the finish action (and any that follow them) and then use a regrade of the attempt to reset everything else.&lt;br /&gt;
&lt;br /&gt;
Actually, it is much easier to re-open an &#039;&#039;&#039;Abandoned&#039;&#039;&#039; attempt than a &#039;&#039;&#039;Finished&#039;&#039;&#039; one. Perhaps we should consider them two different transitions, or perhaps reopening an &#039;&#039;&#039;Abandoned&#039;&#039;&#039; attempt can be treated the same as Time limit extended.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Count this anyway===&lt;br /&gt;
&lt;br /&gt;
Goes from: Abandoned&lt;br /&gt;
&lt;br /&gt;
Goes to: Submitted&lt;br /&gt;
&lt;br /&gt;
Allowed when: The current user has the appropriate capability.&lt;br /&gt;
&lt;br /&gt;
(For example a teacher decides that even though the student abandoned their attempt, it should be counted anyway.)&lt;br /&gt;
&lt;br /&gt;
How it is done: Probably clicking a button on the review page or in the quiz reports. This would probably be a POST either to processattempt.php with extra arguments, or to a new script.&lt;br /&gt;
&lt;br /&gt;
What happens: Probably very similar to Submit all and finish.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* MDL-3030 Late quiz attempts should be closed automatically&lt;br /&gt;
* MDL-4309 Ability for late quizzes (with penalty)&lt;br /&gt;
* MDL-35322 Student didn&#039;t submit quiz, status is Never Submitted, version 2.3.1&lt;br /&gt;
* [[Quiz]] developer documentation&lt;br /&gt;
* Draft user documentation: [[Quiz time controls on attempts]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Better_Office_Integrations_3.3&amp;diff=64539</id>
		<title>Better Office Integrations 3.3</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Better_Office_Integrations_3.3&amp;diff=64539"/>
		<updated>2025-02-10T07:47:54Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Better Office Integrations&lt;br /&gt;
|state = Complete&lt;br /&gt;
|tracker = https://tracker.moodle.org/browse/MDL-57794&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=346085&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= Project - Better Office Integrations - Moodle 3.3 =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
This document lists the minimum set of standard features that should be common to a premium standard office integration with Moodle.  This document is not focussed on any particular office system.   It’s likely that G-Suite and Office365 are the initial targets, but other systems could also be implemented in the same way in future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Site config ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 1 ====&lt;br /&gt;
Users affected: Admins&lt;br /&gt;
&lt;br /&gt;
The problem: The integration involves many plugins and there needs to be a single place to disable/enable it.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Single admin setting to completely enable / disable all plugins for this integration.&lt;br /&gt;
&lt;br /&gt;
Criteria for success: &lt;br /&gt;
# Admin can enable / disable the integration with a single setting.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
=== Authentication ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 2 ====&lt;br /&gt;
Users affected: All&lt;br /&gt;
&lt;br /&gt;
The problem: If my Moodle site allows authentication with oauth - I should have all the possible OAuth providers displayed in priority order on the login page.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Extend auth plugins API to support “oauth” authentication. Display the list of enabled OAuth plugins on the login page (in priority order). &lt;br /&gt;
&lt;br /&gt;
Criteria for success: &lt;br /&gt;
# I see a list of “Login with XXX” options on the Moodle login page in priority order with icons and colors from the OAuth provider. &lt;br /&gt;
# Choosing an OAuth provider from the login page should open the external OAuth page in an popup window. When the OAuth is completed the popup window should close and the login page should reload and now be authenticated.&lt;br /&gt;
# If there is no matching Moodle account for the OAuth account - a new Moodle account should be created automatically and the OAuth account should be added to the list of connected OAuth accounts for this Moodle account.&lt;br /&gt;
# If manual authentication is disabled I should not see a username and password field on the login page. (Update - manual authentication cannot be disabled).&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 3 ====&lt;br /&gt;
Users affected: Administrators&lt;br /&gt;
&lt;br /&gt;
The problem: I want to allow users to login with their office accounts - but only if they come from the correct institution.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Admin configuration settings to control the list of accounts allowed to login via OAuth (e.g. regex on username)&lt;br /&gt;
&lt;br /&gt;
Criteria for success: &lt;br /&gt;
# Users can login to Moodle using an office suite account - only if it belongs to the correct institution.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 4 ====&lt;br /&gt;
Users affected: All&lt;br /&gt;
&lt;br /&gt;
The problem: I do not want multiple different accounts to connect to different applications provided by my institution.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Moodle authentication plugin supporting single sign on (OAuth).&lt;br /&gt;
&lt;br /&gt;
Criteria for success: &lt;br /&gt;
# I can login to Moodle using my office account.&lt;br /&gt;
# If my account does not exist in Moodle it is automatically created. &lt;br /&gt;
# I have only one place to manage my account password. &lt;br /&gt;
# If I am logged into Moodle I can access my office applications without re-authenticating.&lt;br /&gt;
# If I am logged into my office applications I can access Moodle without re-authenticating.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 5 ====&lt;br /&gt;
Users affected: All&lt;br /&gt;
&lt;br /&gt;
The problem: I want to access documents in my personal office account, while logged into Moodle with my university login&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Core api in Moodle for managing a list of oauth connected accounts and current sessions.&lt;br /&gt;
&lt;br /&gt;
Criteria for success: &lt;br /&gt;
# I can login to Moodle using my university account (any existing auth method)&lt;br /&gt;
# When I access a resource from the office suite, I am prompted to login with a choice of my linked OAuth accounts (unless I already have a valid session). &lt;br /&gt;
# After logging in I can browse and search from the files connected to the chosen OAuth account.&lt;br /&gt;
# I can choose at any time to switch to a different connected OAuth account without ending my Moodle session.&lt;br /&gt;
# From the front page, I can login directly using an office account&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 6 ====&lt;br /&gt;
Users affected: All&lt;br /&gt;
&lt;br /&gt;
The problem: I want manage the list of OAuth accounts connected to my Moodle account&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Preferences page for managing the list of connected OAuth accounts&lt;br /&gt;
&lt;br /&gt;
Criteria for success: &lt;br /&gt;
# I can see on my preferences page a list of connected OAuth accounts and can add and remove them.&lt;br /&gt;
# I can add a new connected OAuth account for any of the enabled OAuth Authentication plugins.&lt;br /&gt;
# I can login to Moodle using any of my connected accounts from the login page.&lt;br /&gt;
# I can prevent Moodle from creating accounts when someone logs with an oauth account and no matching user is found&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
=== Calendar ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 7 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: Calendar information is difficult to access if it is not aggregated in a single place.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Automatically export the information from the Moodle calendar to the external calendar.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# My external calendar application automatically reflects the information on my Moodle calendar.&lt;br /&gt;
# I should be able to quickly hide / show all the Moodle events in my external calendar.&lt;br /&gt;
# If I cannot easily hide the events in my external calendar, I should be able to easily prevent Moodle from publishing events to it.&lt;br /&gt;
&lt;br /&gt;
Update - This requirement is not possible to fulfill with the existing apis from Google and Microsoft.&lt;br /&gt;
&lt;br /&gt;
=== Files ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 8 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: Users should be able to create files in the office applications and then use the files in Moodle.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Add a repository plugin to Moodle that supports browsing of files in the office application. &lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Any user can upload any office document they have access to wherever Moodle allows a file to be uploaded.&lt;br /&gt;
# They should be able to search or browse the documents in the office system.&lt;br /&gt;
# Once a document has been linked to Moodle. The access restrictions should rely on Moodles systems for capabilities roles etc (If I can see the link in Moodle I should be able to access the document).&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 9 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: I should be able to upload and create documents in the office suite without leaving Moodle. &lt;br /&gt;
&lt;br /&gt;
The proposed solution: Add a direct link to the management interface for Google drive / Microsoft OneDrive.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# When browsing an office suite repository, I can easily open the native browsing interface in a new window.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 10 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: Any file linked or added to Moodle should be available for checking via a plagiarism plugin&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Verify that files linked to an office suite are supported by the plagiarism API&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Verify any user file linked or copied from an office suite is available to the plagiarism API.&lt;br /&gt;
&lt;br /&gt;
Status: The File API allows downloading of files, but no plagiarism plugins exist in core - so no changes were made.&lt;br /&gt;
&lt;br /&gt;
==== REQ 11 ====&lt;br /&gt;
Users affected: Developers&lt;br /&gt;
&lt;br /&gt;
The problem: It is difficult to test and maintain the plagiarism API because we have no core implementations and third party implementations require accounts / setup.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Create a dummy plagiarism plugin (google search?) with no installation requirements.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Developers can install a plagiarism plugin to easily verify the correct functioning of the plagiarism API.&lt;br /&gt;
&lt;br /&gt;
Status: Not complete.&lt;br /&gt;
&lt;br /&gt;
==== REQ 12 ====&lt;br /&gt;
Users affected: Administrators&lt;br /&gt;
&lt;br /&gt;
The problem: Institutions can have policies about where to upload and store files used in Moodle&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Create admin settings for each repository plugin to control the default (link or copy) and optionally disable either option.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# The administrator configured default (link or copy) is automatically chosen when users are browsing files from a repository.&lt;br /&gt;
# If link or copy are disabled by the administrator, they are not available as options for users when browsing files from a repository.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 13 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: Users should be able to easily update a file that has been linked to Moodle&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Allow repository plugins to generate an “edit link” for a document that is displayed in the UI in addition to the link to view the file.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Any user who can update a file in Moodle that was linked from an office system has a direct link in Moodle to edit the file in the office suite.&lt;br /&gt;
# After saving changes to the file in the office suite - anyone who views the file in Moodle should see the latest version of the file.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3 (although there is a single link to the file).&lt;br /&gt;
&lt;br /&gt;
==== REQ 14 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: Files available in Moodle should be available offline, and on the Mobile app.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Verify any read or edit links to files work correctly in the Mobile app. Add download for offline access links to any document where it is available.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# There is a way to download linked files from Moodle for viewing offline.&lt;br /&gt;
# Edit or view links work correctly when used in the Mobile app.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 15 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: Backing up a Moodle course should backup all the externally linked documents.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Verify the behaviour of backup / restore.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Backing up a course with external files should include only references to the files.&lt;br /&gt;
# Restoring a course with linked files to the same site, should restore any files that were previously external links as external links to the same original files.&lt;br /&gt;
# Restoring a course with linked files to a different site not restore the files, but should show warnings instead.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
=== Assignments ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 16 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: It should be possible for activities to control access to a file that has been linked.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Extend the repository API to allow creating folders, copies of files to a new owner, and changing the permissions on a file/folder. Extend the assignment activity to implement a workflow for files used as assignment submissions.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# A student can upload any file they have access to as an assignment submission.&lt;br /&gt;
# A student can override their assignment submission with a later version&lt;br /&gt;
# All members of a group should be able to collaborate on a group submission before adding it as their assignment submission.&lt;br /&gt;
# Teachers should have read / write access to the submitted files.&lt;br /&gt;
# After the files have added to Moodle students should only be able to “read” the file (but they can link a new version of the file as long as they have access to do so).&lt;br /&gt;
# It should be possible for any Moodle plugin to replicate this same workflow via the repository API.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
=== Archiving ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 17 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: If a teacher links to a file in their personal office suite file area, and then the teacher account is deactivated, deleted or disconnected from the office suite - users in the course must still be able to read and write to the file.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: Verify that access to a file is not lost if the office account no longer exists. Store a copy of the file in Moodle to be used if the original file cannot be accessed.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# If a linked file in Moodle is deleted from the office suite - it should still be available to download in Moodle.&lt;br /&gt;
# If the account that linked to a file in an office suite is removed - it should still be possible to download the file in Moodle and ideally it should still be possible to edit the file.&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
==== REQ 18 ====&lt;br /&gt;
Users affected: Administrators&lt;br /&gt;
&lt;br /&gt;
The problem: If files owned by an “Institution” account in the office suite are not organised - it will be impossible to archive no-longer used files at the end of a teaching period.&lt;br /&gt;
&lt;br /&gt;
The proposed solution: All files transferred to an institution account as part of a custom workflow should be organised by course / activity so they can be manually archived as required.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Files used in a custom workflow (e.g. by assignment) should stored in an institutional account, and organised by category / course / activity (reflect the context structure in Moodle).&lt;br /&gt;
&lt;br /&gt;
Status: Completed for Moodle 3.3&lt;br /&gt;
&lt;br /&gt;
=== User Experience ===&lt;br /&gt;
&lt;br /&gt;
==== REQ 19 ====&lt;br /&gt;
Users affected: Students, teachers&lt;br /&gt;
&lt;br /&gt;
The problem: When connected to an office suite - it should be possible to upload or create a file in the office suite with a minimum number of steps. &lt;br /&gt;
&lt;br /&gt;
The proposed solution: When using the file picker, there should be a direct link to the native browsing interface which provides the best experience for uploading and creating new files.&lt;br /&gt;
&lt;br /&gt;
The criteria for success:&lt;br /&gt;
# Each repository should have a direct link to the native browsing interface.&lt;br /&gt;
&lt;br /&gt;
Status: This requirement was not addressed for Moodle 3.3. It should really be done as a bigger project reviewing the UX of the file picker entirely.&lt;br /&gt;
&lt;br /&gt;
== Technical Specifications ==&lt;br /&gt;
&lt;br /&gt;
This section of the document describes the changes that need to be made in Moodle in order to meet the success criteria of each of the requirements for this project. These specifications describe the design of each of the Office 365 and Google Apps integrations and so each section needs to be implemented twice - once for each integration.&lt;br /&gt;
&lt;br /&gt;
=== Core API for managing Authorized OAuth Applications ===&lt;br /&gt;
There should be a new preference page and API to manage the list of a users authorized oauth applications.&lt;br /&gt;
&lt;br /&gt;
This requires a new DB tables to store the system wide OAuth clients and the current users active oauth sessions should be stored in the current PHP session. &lt;br /&gt;
&lt;br /&gt;
mdl_oauth2_clients&lt;br /&gt;
&lt;br /&gt;
# clientid - varchar(100) - NOT NULL&lt;br /&gt;
# secret - varchar(100) - NOT NULL&lt;br /&gt;
# refreshtoken - varchar(255) - NULL&lt;br /&gt;
# systemuser - varchar(255) - NULL&lt;br /&gt;
# apirooturl - varchar(255) - NOT NULL&lt;br /&gt;
# apirequesttokenurl - varchar(255) - NOT NULL&lt;br /&gt;
# apiaccesstokenurl - varchar(255) - NOT NULL&lt;br /&gt;
&lt;br /&gt;
The apirooturl + apirequesttokenurl + apiaccesstokenurl form a unique key. It is possible to retrieve the stored clientid and secret using the 3 api url parameters.&lt;br /&gt;
&lt;br /&gt;
The refresh token here is used to get an access token for the system account.&lt;br /&gt;
&lt;br /&gt;
The systemuser is the unique identifier required to access resources using a system account rather than the current users account.&lt;br /&gt;
&lt;br /&gt;
==== Notes (after prototyping). ====&lt;br /&gt;
&lt;br /&gt;
Open ID Connect is the SSO standard built on top of OAuth 2.0. Google supports it well and Microsoft claim to - but their implementation is not functional/usable.&lt;br /&gt;
&lt;br /&gt;
Problems with Microsoft Open ID Connect implementation (their side not ours):&lt;br /&gt;
&lt;br /&gt;
# It&#039;s userinfo endpoint is missing email and picture claims.&lt;br /&gt;
# The discovery document points to the wrong api version (1.0 instead of 2.0)&lt;br /&gt;
# The tokens from the Open ID Connect token endpoint are not usable with the graph API (because of b)&lt;br /&gt;
# The tokens from the alternative OAuth 2.0 endpoints are not compatible with the OpenID Connect endpoints (userinfo).&lt;br /&gt;
# Not necessarily a problem but the sup claim from Microsoft is a massive unreadable string which is not nice for a username (but is guaranteed unique).&lt;br /&gt;
&lt;br /&gt;
=== Extend Auth Plugin API ===&lt;br /&gt;
The existing Auth Plugin API should allow plugins to register themselves as &amp;quot;OAuth 2 &amp;quot; compatible. This will allow them to be listed on the login page in priority order with icons and coloured buttons. The order of the buttons should be determined by the order of the auth plugin.&lt;br /&gt;
&lt;br /&gt;
=== Auth plugin ===&lt;br /&gt;
Implement a new authentication plugin that is &amp;quot;OAuth 2&amp;quot; compatible and is preconfigured to talk to the office suite. &lt;br /&gt;
&lt;br /&gt;
Provide admin settings to limit the valid domains / institutions that can authenticate with this plugin. &lt;br /&gt;
&lt;br /&gt;
Add a setting to allow self registration with this plugin so that accounts can be automatically created if the authentication is successful and no matching account exists.&lt;br /&gt;
&lt;br /&gt;
When an account is connected with this auth plugin - the Moodle calendar rss url should be published to the Office calendar automatically.&lt;br /&gt;
&lt;br /&gt;
There should be a setting to disable the automatic publishing of calendars.&lt;br /&gt;
&lt;br /&gt;
=== Admin tool to manage integration settings ===&lt;br /&gt;
&lt;br /&gt;
An admin tool needs to be created which contains the required information in order to access the office suite API using OAuth as well as a valid access token for a institutional administrator account.&lt;br /&gt;
&lt;br /&gt;
This plugin needs a global on/off switch which enabled or disables the entire office suite integration (config value stored in mdl_config_plugins).&lt;br /&gt;
&lt;br /&gt;
This plugin should have settings to create an entry in the mdl_oauth2_clients table.&lt;br /&gt;
&lt;br /&gt;
The workflow for setting up the plugin would be to enter the client id and secret, then follow a link in the admin tool to authenticate the institutional account via OAuth 2. The refresh token for the institution account will be stored in the database - and used whenever we need to access the API as the &amp;quot;institution&amp;quot; rather than the current user.&lt;br /&gt;
&lt;br /&gt;
=== Repository API ===&lt;br /&gt;
&lt;br /&gt;
The repository api needs to be extended so that repositories can support advanced workflows for files.&lt;br /&gt;
&lt;br /&gt;
Repository plugins should be able to register that they are OAuth compatible. This will enable an additional configuration page for the plugin which allows setting up the system account and authorizing a refresh token for this system user. The refresh token will then be used by the repository plugin to generate an access token when it needs to perform an operation as the system user.&lt;br /&gt;
&lt;br /&gt;
The additional functionality required is:&lt;br /&gt;
&lt;br /&gt;
get_edit_link() - retrieve a link to edit this file in an external application. If supported will show an additional link or menu entry when the file is listed to &amp;quot;edit this file&amp;quot;. Moodle will only generate and display this link to users who have access to edit the file in Moodle. The external repository should allow editing from any user who follows this link regardless of the permissions in the external repository.&lt;br /&gt;
&lt;br /&gt;
get_offline_link() - for external files (links), retrieve a link to download this file in a format that is suitable for viewing offline - e.g. PDF. Moodle will only generate and display this link to users who have access to read the file in Moodle. The external repository should allow viewing from any user who follows this link regardless of the permissions in the external repository.&lt;br /&gt;
&lt;br /&gt;
copy_to_system_account() - copy a file from the users file area in the external repository - to new file in a system owned file area in the external repository organised by category, course and activity. This is used as part of an activity workflow when the file switches from being editable by the original author - to being editable by a different group of users (teachers most likely).&lt;br /&gt;
&lt;br /&gt;
=== Repository Plugin ===&lt;br /&gt;
Implement a new plugin for this office suite that allows browsing and searching the users currently authorized (OAuth) file area. If there is no valid OAuth session for this OAuth client API the OAuth login screen should be presented to create a new session.&lt;br /&gt;
&lt;br /&gt;
This plugin should also support all of the new functionality for repository plugins listed in Repository API above.&lt;br /&gt;
&lt;br /&gt;
This plugin should also support uploading and creating new files in the repository while browsing / searching.&lt;br /&gt;
&lt;br /&gt;
This plugin should contain a setting to &amp;quot;download for archive&amp;quot; which should download an offline copy of each file - even if was created as a link and store it in Moodle. If enabled the &amp;quot;offline&amp;quot; version of this file will be served from Moodle always and included in backup/restore. Offline versions of files should be refreshed by a cron task and an adhoc task should be created to check for a newer version when a file is accessed.&lt;br /&gt;
&lt;br /&gt;
This plugin should have a setting to say if the default for files added to Moodle is &amp;quot;link&amp;quot; or &amp;quot;copy&amp;quot;. It should be possible to disable &amp;quot;link&amp;quot; or &amp;quot;copy&amp;quot; (but not both).&lt;br /&gt;
&lt;br /&gt;
=== Assignment Improvements ===&lt;br /&gt;
The assignment should check if the repository plugin supports the advanced workflow for submissions files. If it does - it should copy the submission file to a system account at the point that it is &amp;quot;submitted&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Improvements to the File Picker ===&lt;br /&gt;
If there are any enabled repositories that report they support uploading of files - a new button should be added to the file manager &amp;quot;Upload file&amp;quot; which will open the file picker with the first &amp;quot;upload&amp;quot; repository already selected.&lt;br /&gt;
&lt;br /&gt;
=== Plagiarism API ===&lt;br /&gt;
Extend the plagiarism API to check if a repository supports &amp;quot;offline&amp;quot; links. If it does - the offline version of files should be downloaded and used by the plagiarism API as normal.&lt;br /&gt;
&lt;br /&gt;
=== Plagiarism Plugin ===&lt;br /&gt;
Implement a dummy plagiarism plugin to make testing easier. It should support all features of the plagiarism API but does not have to return real data.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Backup_2.0_course_report_data&amp;diff=64538</id>
		<title>Backup 2.0 course report data</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Backup_2.0_course_report_data&amp;diff=64538"/>
		<updated>2025-02-10T07:46:12Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Template:Backup 2.0}}{{Moodle_2.0}}{{Update}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notice: Since Moodle 2.2, the admin reports and course report have been merged into a single reports subsystem. This page does not reflect this change yet. It is valid for 2.0 and 2.1 versions.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2, course reports can have data tables and files which can be backed up with a course. (To create data tables in a course report, use the standard &amp;lt;tt&amp;gt;db&amp;lt;/tt&amp;gt; folder.)&lt;br /&gt;
&lt;br /&gt;
None of the standard course reports have any course-related data so it is not obvious how to code the backup and restore for them. This page gives an example theme as a case study which you can use to implement your own backup code for a course report which contains per-course data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: Course report data backup requires Moodle 2.0.4 or later.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Example: the &#039;lazystudents&#039; report ==&lt;br /&gt;
&lt;br /&gt;
As an example I am using a theoretical report which checks the time that each user visits Moodle on each day over the past week. The report produces a list of students who did not access Moodle before a certain time on any day last week. For example, this might include all students who never accessed Moodle before 10:00 on any day last week.&lt;br /&gt;
&lt;br /&gt;
The report has two configuration options which can both be set per-course:&lt;br /&gt;
&lt;br /&gt;
* The hour after which students are considered &#039;lazy&#039; (e.g. 10). &lt;br /&gt;
&lt;br /&gt;
* A custom image to display with the report (e.g. some courses might prefer a tortoise picture while others prefer a sloth).&lt;br /&gt;
&lt;br /&gt;
The hour is stored in the table &amp;lt;tt&amp;gt;coursereport_lazystudents&amp;lt;/tt&amp;gt; which has 3 fields &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;courseid&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;lazyhour&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The image file is stored using the Moodle file API at the course context, in the &amp;lt;tt&amp;gt;coursereport_lazystudents&amp;lt;/tt&amp;gt; component and the &amp;lt;tt&amp;gt;image&amp;lt;/tt&amp;gt; file area.&lt;br /&gt;
&lt;br /&gt;
=== Backup ===&lt;br /&gt;
&lt;br /&gt;
The backup code is in the file &amp;lt;tt&amp;gt;course/report/lazystudents/backup/moodle2/backup_coursereport_lazystudents_plugin.class.php&amp;lt;/tt&amp;gt;. Leaving out the headers, this file looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 class backup_coursereport_lazystudents_plugin extends backup_coursereport_plugin {&lt;br /&gt;
 &lt;br /&gt;
     /**&lt;br /&gt;
      * Returns the course report information to attach to course element&lt;br /&gt;
      */&lt;br /&gt;
     protected function define_course_plugin_structure() {&lt;br /&gt;
         // Define virtual plugin element&lt;br /&gt;
         $plugin = $this-&amp;gt;get_plugin_element(null, $this-&amp;gt;get_include_condition(), &#039;include&#039;);&lt;br /&gt;
 &lt;br /&gt;
         // Create plugin container element with standard name&lt;br /&gt;
         $pluginwrapper = new backup_nested_element($this-&amp;gt;get_recommended_name());&lt;br /&gt;
 &lt;br /&gt;
         // Add wrapper to plugin&lt;br /&gt;
         $plugin-&amp;gt;add_child($pluginwrapper);&lt;br /&gt;
 &lt;br /&gt;
         // Set up course report&#039;s own structure and add to wrapper&lt;br /&gt;
         $lazystudents = new backup_nested_element(&#039;lazystudents&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
             &#039;lazyhour&#039;));&lt;br /&gt;
         $pluginwrapper-&amp;gt;add_child($lazystudents);&lt;br /&gt;
 &lt;br /&gt;
         // Use database to get source&lt;br /&gt;
         $lazystudents-&amp;gt;set_source_table(&#039;coursereport_lazystudents&#039;,&lt;br /&gt;
                 array(&#039;courseid&#039; =&amp;gt; backup::VAR_COURSEID));&lt;br /&gt;
 &lt;br /&gt;
         // Include files which have coursereport_lazystudents and area image and no itemid&lt;br /&gt;
         $lazystudents-&amp;gt;annotate_files(&#039;coursereport_lazystudents&#039;, &#039;image&#039;, null);&lt;br /&gt;
 &lt;br /&gt;
         return $plugin;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Returns a condition for whether we include this report in the backup&lt;br /&gt;
     * or not. We do that based on if it has any settings in the table.&lt;br /&gt;
     * @return array Condition array&lt;br /&gt;
     */&lt;br /&gt;
    protected function get_include_condition() {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        if ($DB-&amp;gt;record_exists(&#039;coursereport_lazystudents&#039;,&lt;br /&gt;
                array(&#039;courseid&#039; =&amp;gt; $this-&amp;gt;task-&amp;gt;get_courseid()))) {&lt;br /&gt;
            $result = &#039;include&#039;;&lt;br /&gt;
        } else {&lt;br /&gt;
            $result = &#039;&#039;;&lt;br /&gt;
        }&lt;br /&gt;
        return array(&#039;sqlparam&#039; =&amp;gt; $result);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
As you can see this works in a similar way to backup for modules and other plugins. The first line:&lt;br /&gt;
&lt;br /&gt;
 $plugin = $this-&amp;gt;get_plugin_element(null, $this-&amp;gt;get_include_condition(), &#039;include&#039;);&lt;br /&gt;
&lt;br /&gt;
means that the format data will only be backed up if the get_include_condition function returns true (i.e. it won&#039;t bother backing up data for a course report that does not have settings on the particular course).&lt;br /&gt;
&lt;br /&gt;
You can see how you would change the code to use a different course report name, database table, fields, or file area. It&#039;s also possible to add a more complicated data structured in the same way as for other plugins. You could even store user data if required.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
To test the backup, carry it out and then look inside the resulting zip file. In the &amp;lt;tt&amp;gt;course&amp;lt;/tt&amp;gt; folder there should be a file called &amp;lt;tt&amp;gt;course.xml&amp;lt;/tt&amp;gt;. If course report data is backed up, it will include a section like the following:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;plugin_coursereport_lazystudents_course&amp;gt;&lt;br /&gt;
  &amp;lt;lazystudents id=&amp;quot;2&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;lazyhour&amp;gt;10&amp;lt;/lazyhour&amp;gt;&lt;br /&gt;
  &amp;lt;/lazystudents&amp;gt;&lt;br /&gt;
 &amp;lt;/plugin_coursereport_lazystudents_course&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Additionally, if the file backup worked, you should be able to find any files from within the specified file area inside the &#039;files&#039; section of the backup (it will help if you know the hash code of the file; otherwise, note the size and make sure the test course doesn&#039;t have many other files to look through).&lt;br /&gt;
&lt;br /&gt;
If there is no data in the table, the course report will not be backed up at all and this section will not be included in course.xml.&lt;br /&gt;
&lt;br /&gt;
=== Restore ===&lt;br /&gt;
&lt;br /&gt;
Unsurprisingly, restore code goes in the file &amp;lt;tt&amp;gt;course/report/lazystudents/backup/moodle2/restore_coursereport_lazystudents_plugin.class.php&amp;lt;/tt&amp;gt;. Leaving out the headers, this file is:&lt;br /&gt;
&lt;br /&gt;
 class restore_coursereport_lazystudents_plugin extends restore_coursereport_plugin {&lt;br /&gt;
 &lt;br /&gt;
     /**&lt;br /&gt;
      * Returns the paths to be handled by the plugin at course level&lt;br /&gt;
      */&lt;br /&gt;
     protected function define_course_plugin_structure() {&lt;br /&gt;
         $paths = array();&lt;br /&gt;
 &lt;br /&gt;
         // Because of using get_recommended_name() it is able to find the&lt;br /&gt;
         // correct path just by using the part inside the element name (which&lt;br /&gt;
         // only has a /lazystudents element).&lt;br /&gt;
         $elepath = $this-&amp;gt;get_pathfor(&#039;/lazystudents&#039;);&lt;br /&gt;
 &lt;br /&gt;
         // The &#039;lazystudents&#039; here defines that it will use the&lt;br /&gt;
         // process_lazystudents function to restore its element.&lt;br /&gt;
         $paths[] = new restore_path_element(&#039;lazystudents&#039;, $elepath);&lt;br /&gt;
 &lt;br /&gt;
         return $paths;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     /**&lt;br /&gt;
      * Called after this runs for a course.&lt;br /&gt;
      */&lt;br /&gt;
     function after_execute_course() {&lt;br /&gt;
         // Need to restore file&lt;br /&gt;
         $this-&amp;gt;add_related_files(&#039;coursereport_lazystudents&#039;, &#039;image&#039;, null);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     /**&lt;br /&gt;
      * Process the &#039;lazystudents&#039; element&lt;br /&gt;
      */&lt;br /&gt;
     public function process_lazystudents($data) {&lt;br /&gt;
         global $DB;&lt;br /&gt;
 &lt;br /&gt;
         // Get data record ready to insert in database&lt;br /&gt;
         $data = (object)$data;&lt;br /&gt;
         $data-&amp;gt;courseid = $this-&amp;gt;task-&amp;gt;get_courseid();&lt;br /&gt;
 &lt;br /&gt;
         // See if there is an existing record for this course&lt;br /&gt;
         $existingid = $DB-&amp;gt;get_field(&#039;coursereport_lazystudents&#039;, &#039;id&#039;,&lt;br /&gt;
                 array(&#039;courseid&#039;=&amp;gt;$data-&amp;gt;courseid));&lt;br /&gt;
         if ($existingid) {&lt;br /&gt;
             $data-&amp;gt;id = $existingid;&lt;br /&gt;
             $DB-&amp;gt;update_record(&#039;coursereport_lazystudents&#039;, data);&lt;br /&gt;
         } else {&lt;br /&gt;
             $DB-&amp;gt;insert_record(&#039;coursereport_lazystudents&#039;, $data);&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // No need to record the old/new id as nothing ever refers to&lt;br /&gt;
         // the id of this table.&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Again this is just the same as restoring a module. To change this to support your own course report, you would change the word &#039;lazystudents&#039; to your own course report&#039;s name, change references to the &amp;lt;tt&amp;gt;coursereport_lazystudents&amp;lt;/tt&amp;gt; table to your own data table (or otherwise change what exactly it does when restoring), and change the file area details in the &amp;lt;tt&amp;gt;add_related_files&amp;lt;/tt&amp;gt; call.&lt;br /&gt;
&lt;br /&gt;
The restore code always runs if the data was included in the backup.&lt;br /&gt;
&lt;br /&gt;
==== Testing ====&lt;br /&gt;
&lt;br /&gt;
It is probably obvious how to test restore :) Once you&#039;ve verified that backup is producing the correct XML data, just check that restore recreates the necessary data for you. &lt;br /&gt;
&lt;br /&gt;
In our case, we know restore works if the lazy hour value for the new course is correctly set, and the sloth picture is correctly displayed.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Backup_2.0_XML_format&amp;diff=64537</id>
		<title>Backup 2.0 XML format</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Backup_2.0_XML_format&amp;diff=64537"/>
		<updated>2025-02-10T07:45:42Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
We need some content here!  :)&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Backup_1.9_conversion_for_developers&amp;diff=64536</id>
		<title>Backup 1.9 conversion for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Backup_1.9_conversion_for_developers&amp;diff=64536"/>
		<updated>2025-02-10T07:45:27Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Tutorial for developers on backup 1.9 conversion&lt;br /&gt;
|state = Ready to use&lt;br /&gt;
|tracker = MDL-22414&lt;br /&gt;
|discussion = N/A&lt;br /&gt;
|assignee = [[User:David Mudrak|David Mudrak]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
[[Image:zip2mbz.png|right]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This page follows up the tutorial at [[Backup 2.0 for developers]] and describes how to implement support of Moodle 1.9 backup conversion into the new Moodle 2.x format.&lt;br /&gt;
&lt;br /&gt;
In short, since Moodle 2.1 there is a new type of core component available called &#039;&#039;backup converters&#039;&#039;. Converter is a tool that takes a directory containing some Moodle course data and converts it into another format. At the moment we are working on converter called &#039;&#039;&#039;moodle1&#039;&#039;&#039; that supports 1.9 =&amp;gt; 2.x conversion path. In the future, more converters can be written (eg supporting custom formats, Blackboard, IMS CC etc). Converters can be chained so if there is a converter that supports IMS =&amp;gt; 1.9 conversion and another one converting 1.9 =&amp;gt; 2.x, Moodle can automatically restore IMS backups. The core of the moodle1 converter is implemented in backup/converter/moodle1/.&lt;br /&gt;
&lt;br /&gt;
The moodle1 converter is under a heavy development at the moment still. The first milestone is to be able to convert all activity modules without user data.&lt;br /&gt;
&lt;br /&gt;
== Getting familiar with the required changes of the structure ==&lt;br /&gt;
&lt;br /&gt;
For the purpose of this tutorial, the [[Choice module]] is used as an example as it allows to demonstrate the basic workflow of the conversion. Let us start with performing a backup in both 1.9 and 2.1. Create an empty course with a single simple Choice module instance inside in both 1.9 and 2.1. Choose backup mode without any user data, without roles, files etc and include just the instance of the module you created.&lt;br /&gt;
&lt;br /&gt;
In case of Moodle 1.9, you will end up having once monolithic file moodle.xml. In Moodle 2.1, the module data will be stored in a file like activities/choice_x/choice.xml. The task of the converter you are going to write is to convert data contained in moodle.xml into choice.xml.&lt;br /&gt;
&lt;br /&gt;
=== Getting the list of XML paths ===&lt;br /&gt;
&lt;br /&gt;
Looking at moodle.xml in 1.9 backup, you can see that the module data are stored in XML nodes at /MOODLE_BACKUP/COURSE/MODULES/MOD and that you are interested only to those MODs having &amp;lt;MODTYPE&amp;gt;choice&amp;lt;/MODTYPE&amp;gt;. To make your life easier, the core of the moodle1 converter injects one virtual node into the path so that to our module, it appears as if its data were in /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE. That is as if all Choice data were wrapped by yet another tag in moodle.xml.&lt;br /&gt;
&lt;br /&gt;
Now look into 1.9 Moodle code and locate the file mod/choice/backuplib.php. Reading its code you can see that the MOD element in moodle.xml (that will be presented as MOD/CHOICE element to our code) contains the following tags holding the corresponding fields from mdl_choice table:&lt;br /&gt;
&lt;br /&gt;
    ID              $choice-&amp;gt;id&lt;br /&gt;
    NAME            $choice-&amp;gt;name&lt;br /&gt;
    TEXT            $choice-&amp;gt;text&lt;br /&gt;
    FORMAT          $choice-&amp;gt;format&lt;br /&gt;
    PUBLISH         $choice-&amp;gt;publish&lt;br /&gt;
    SHOWRESULTS     $choice-&amp;gt;showresults&lt;br /&gt;
    DISPLAY         $choice-&amp;gt;display&lt;br /&gt;
    ALLOWUPDATE     $choice-&amp;gt;allowupdate&lt;br /&gt;
    SHOWUNANSWERED  $choice-&amp;gt;showunanswered&lt;br /&gt;
    LIMITANSWERS    $choice-&amp;gt;limitanswers&lt;br /&gt;
    TIMEOPEN        $choice-&amp;gt;timeopen&lt;br /&gt;
    TIMECLOSE       $choice-&amp;gt;timeclose&lt;br /&gt;
    TIMEMODIFIED    $choice-&amp;gt;timemodified&lt;br /&gt;
&lt;br /&gt;
Below these, the choice options data are dumped into the OPTIONS section, with each option details being wrapped by the OPTION tag:&lt;br /&gt;
&lt;br /&gt;
    ID              $cho_opt-&amp;gt;id&lt;br /&gt;
    TEXT            $cho_opt-&amp;gt;text&lt;br /&gt;
    MAXANSWERS      $cho_opt-&amp;gt;maxanswers&lt;br /&gt;
    TIMEMODIFIED    $cho_opt-&amp;gt;timemodified&lt;br /&gt;
&lt;br /&gt;
The file moodle.xml will be parsed by a progressive parser. That basically means it will be read in a sequential order and each time some interesting path is reached, the data contained by that element are dispatched to a handler (on contrary to DOM like parsers where the whole file would be converted into a huge in-memory tree structure). To catch the choice data in moodle.xml we will have to handle /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE and /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE/OPTIONS/OPTION paths&lt;br /&gt;
&lt;br /&gt;
=== Getting know how data change during 1.9 =&amp;gt; 2.x upgrade ===&lt;br /&gt;
&lt;br /&gt;
Now let us open mod/choice/db/upgrade.php in your Moodle 2.1 code. It contains all the upgrade logic that is happening during the upgrade of 1.9 site to 2.x. Reading the code, we realize that:&lt;br /&gt;
&lt;br /&gt;
* the database field &#039;&#039;text&#039;&#039; in the {choice} table is renamed to &#039;&#039;intro&#039;&#039;&lt;br /&gt;
* the database field &#039;&#039;format&#039;&#039; in the {choice} table is renamed to &#039;&#039;introformat&#039;&#039;&lt;br /&gt;
* a new field &#039;&#039;completionsubmit&#039;&#039; is added to the {choice} table with the default value 0&lt;br /&gt;
&lt;br /&gt;
=== Getting know the structure of choice.xml ===&lt;br /&gt;
&lt;br /&gt;
Finally look at mod/choice/backup/moodle2/ in your Moodle 2.1, particularly the file backup_choice_stepslib.php. Here you can see how the structure of the choice.xml is defined and what data it contains:&lt;br /&gt;
&lt;br /&gt;
    $choice = new backup_nested_element(&#039;choice&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
        &#039;name&#039;, &#039;intro&#039;, &#039;introformat&#039;, &#039;publish&#039;,&lt;br /&gt;
        &#039;showresults&#039;, &#039;display&#039;, &#039;allowupdate&#039;, &#039;allowunanswered&#039;,&lt;br /&gt;
        &#039;limitanswers&#039;, &#039;timeopen&#039;, &#039;timeclose&#039;, &#039;timemodified&#039;,&lt;br /&gt;
        &#039;completionsubmit&#039;));&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;choice&amp;gt; element has a child element &amp;lt;options&amp;gt; that in turn contains set of &amp;lt;option&amp;gt; elements:&lt;br /&gt;
&lt;br /&gt;
    $option = new backup_nested_element(&#039;option&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
        &#039;text&#039;, &#039;maxanswers&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
Great! Now we have all the information needed to start with coding.&lt;br /&gt;
&lt;br /&gt;
=== Summary ===&lt;br /&gt;
&lt;br /&gt;
Do not continue your task unless&lt;br /&gt;
&lt;br /&gt;
* you have read the backuplib.php in 1.9 source of the module and you know how the &amp;lt;MOD&amp;gt; node in moodle.xml is constructed (do not rely on just looking at some example file)&lt;br /&gt;
* you have read the db/upgrade.php and you known all steps needed to perform&lt;br /&gt;
* you have read backup/moodle2/backup_xxx_stepslib.php and you know how the activity file in 2.0 is constructed (again, do not rely on examples)&lt;br /&gt;
&lt;br /&gt;
== Writing the conversion handler ==&lt;br /&gt;
&lt;br /&gt;
Before we start, please make your own local branch that will track David&#039;s https://github.com/mudrd8mz/moodle/tree/backup-convert tree. That is the pre-integration branch where the development of backup conversion is happening and your work will have to be merged there before it gets into the moodle.git master (use Github&#039;s pull request feature once you want your work being included there).&lt;br /&gt;
&lt;br /&gt;
To add this branch into your current moodle.git clone, you may want to use something like this:&lt;br /&gt;
&lt;br /&gt;
    $ cd ~/public_html/moodle21&lt;br /&gt;
    $ git remote add mudrd8mz git://github.com/mudrd8mz/moodle.git&lt;br /&gt;
    $ git fetch mudrd8mz&lt;br /&gt;
    $ git checkout --track -b backup-convert mudrd8mz/backup-convert&lt;br /&gt;
&lt;br /&gt;
Alternatively, if you want to create a pristine installation just for this project, you can simply run&lt;br /&gt;
&lt;br /&gt;
    $ cd ~/public_html&lt;br /&gt;
    $ git clone git://github.com/mudrd8mz/moodle.git moodle21convert&lt;br /&gt;
    $ cd moodle21convert&lt;br /&gt;
    $ git checkout --track -b backup-convert origin/backup-convert&lt;br /&gt;
&lt;br /&gt;
=== The backup conversion workflow ===&lt;br /&gt;
&lt;br /&gt;
To be able to write the module conversion handler, you should understand what&#039;s going on in the background. This is a simplified description of the workflow:&lt;br /&gt;
&lt;br /&gt;
[[image:backup-convert-overview.png|thumb|UML sequence diagram of the backup conversion machinery]]&lt;br /&gt;
&lt;br /&gt;
* In its constructor, the restore_controller instance detects the format of the data to be restored and if it realizes it is not the standard moodle2 format, it knows the conversion will be needed (grep for backup::STATUS_REQUIRE_CONV)&lt;br /&gt;
* The restore_controller::convert() method is called (@todo is it? where? by who?) and it in turn calls convert_helper::to_moodle2_format(). This helper method tries to find the most effective conversion path between the current format and the target moodle2 format as it constructs the chain of converters, though this is not much interesting yet as we have just one converter now ... well not yet even :-p&lt;br /&gt;
* For each converter in the chain, convert_factory::get_converter() creates new instance of it and its public convert() method is called.&lt;br /&gt;
* The core functionality of moodle1 converter is defined in backup/converter/moodle1/lib.php in the class moodle1_converter and its subclasses. When the class is instantiated, it prepares a progressive parser and a parser processor and it registers all available handlers of the parsed data. The incoming convert() call sets up the directory to write to and runs the instance&#039;s execute() method.&lt;br /&gt;
* The execute() starts up the parser of the 1.9 moodle.xml. That file is parsed sequentially and whenever it reaches a node to which some handler is attached, it dispatches the parsed data via dispatch_chunk(). The parser also triggers notify_path_start() and notify_path_end() when it is entering some registered path element and when it is leaving it.&lt;br /&gt;
* The parser processor re-dispatches the parsed data and events via path_start_reached(), process_chunk() and path_end_reached() methods defined by the moodle1_convert.&lt;br /&gt;
* Finally, the parsed data and events are re-dispatched once more and they are handled by moodle1_handler subclasses via their on_xxx_start(), process_xxx() and on_xxx_end() methods. These are the places where the actual conversion of data must happen and the new data are written into the new XML files.&lt;br /&gt;
* The moodle1_handler subclasses can use either xml_writer&#039;s begin_tag(), full_tag() and end_tag() method to construct the XML file contents. A helper method that dumps a complete tree-ish structure is available: write_xml().&lt;br /&gt;
&lt;br /&gt;
After the end of the parsed moodle.xml file is reached, the working directory with the new XML files is renamed so that it replaces the previous format. If there was a chain of converters, it would be the next one&#039;s round now. For us at the moment, the job is done. Once the directory contains valid moodle2 format, normal restore process is executed as if the course backup come from a 2.0 server.&lt;br /&gt;
&lt;br /&gt;
==== Highlights and places to look at ====&lt;br /&gt;
&lt;br /&gt;
While working on the converter, always keep in mind:&lt;br /&gt;
&lt;br /&gt;
* The file moodle.xml is parsed sequentially by a progressive parser. If the current node&#039;s data are available, the handler must either write them immediately into a new XML file or stash them for processing them later - either by the on_element_end() event handler method or by other instance of the handler that is being executed later.&lt;br /&gt;
* Minimise the memory footprint of the conversion job. Do not accumulate the incoming data in memory if it is not necessary. Especially those that may be huge (like all forum posts). Write the data to the new XML file as soon as possible (on-the-fly ideally but that is not always possible).&lt;br /&gt;
* Look at various examples of moodle1 handler classes in backup/converter/moodle1/handlerlib.php&lt;br /&gt;
&lt;br /&gt;
=== The handler library template ===&lt;br /&gt;
&lt;br /&gt;
The moodle1_converter itself converts just part of the moodle.xml file via handlers defined in handlerlib.php (for example the course sections, course modules etc). To convert module-specific data, moodle1_handlers_factory searches for the handlers in modules&#039; (and generally plugins&#039;) directories. The Choice module conversion logic is stored in a library mod/choice/backup/moodle1/lib.php. The basic template for such a file is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Provides support for the conversion of moodle1 backup to the moodle2 format&lt;br /&gt;
 *&lt;br /&gt;
 * @package    mod&lt;br /&gt;
 * @subpackage choice&lt;br /&gt;
 * @copyright  2011 Your Name &amp;lt;your@email&amp;gt;&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Choice conversion handler&lt;br /&gt;
 */&lt;br /&gt;
class moodle1_mod_choice_handler extends moodle1_mod_handler {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Declare the paths in moodle.xml we are able to convert&lt;br /&gt;
     *&lt;br /&gt;
     * The method returns list of {@link convert_path} instances. For each path returned,&lt;br /&gt;
     * at least one of on_xxx_start(), process_xxx() and on_xxx_end() methods must be&lt;br /&gt;
     * defined. The method process_xxx() is not executed if the associated path element is&lt;br /&gt;
     * empty (i.e. it contains none elements or sub-paths only).&lt;br /&gt;
     *&lt;br /&gt;
     * Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE does not&lt;br /&gt;
     * actually exist in the file. The last element with the module name was&lt;br /&gt;
     * appended by the moodle1_converter class.&lt;br /&gt;
     *&lt;br /&gt;
     * @return array of {@link convert_path} instances&lt;br /&gt;
     */&lt;br /&gt;
    public function get_paths() {&lt;br /&gt;
        return array(&lt;br /&gt;
            new convert_path(&#039;choice&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE&#039;),&lt;br /&gt;
            new convert_path(&#039;choice_option&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE/OPTIONS/OPTION&#039;),&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE&lt;br /&gt;
     * data available&lt;br /&gt;
     */&lt;br /&gt;
    public function process_choice($data) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE/OPTIONS/OPTION&lt;br /&gt;
     * data available&lt;br /&gt;
     */&lt;br /&gt;
    public function process_choice_option($data) {&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us look at this code template closer so that you understand the bits and will be able to use it as a template for your own work.&lt;br /&gt;
&lt;br /&gt;
As you can see, the file defines a single class that extends moodle1_mod_handler. All moodle1 handler classes must define get_paths() public method that returns a list of convert_path instances. In our example, we declare that the handler is interested in those two paths we have identified above. We register them with &amp;quot;aliases&amp;quot; &#039;&#039;choice&#039;&#039; and &#039;&#039;choice_option&#039;&#039;. The developer can choose any reasonable alias here and provide it as the first parameter of the convert_path constructor.&lt;br /&gt;
&lt;br /&gt;
For each convert_path instance, a corresponding processing method must exist in the class. This method must be named process_xxx() where xxx is the alias declared in the get_paths().&lt;br /&gt;
&lt;br /&gt;
=== Setting-up the development environment ===&lt;br /&gt;
&lt;br /&gt;
Use a real 1.9 backup file and unzip it into a folder within your $CFG-&amp;gt;dataroot.&#039;/temp/backup/&#039; directory. Let us assume you have unzipped the backup into a folder called &#039;&#039;refcourse&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Put the following script into the root of your Moodle (as &#039;convert.php&#039; for example):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
define(&#039;CLI_SCRIPT&#039;, 1);&lt;br /&gt;
require(dirname(__FILE__).&#039;/config.php&#039;);&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/backup/util/helper/convert_helper.class.php&#039;);&lt;br /&gt;
&lt;br /&gt;
convert_helper::to_moodle2_format(&#039;refcourse&#039;, &#039;moodle1&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(if you do not want to execute the script via CLI but from your browser, just remove the CLI_SCRIPT declaration).&lt;br /&gt;
&lt;br /&gt;
Put the following into your config.php:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;keeptempdirectoriesonbackup = true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The convert.php script in the Moodle root converts the &#039;refcourse&#039; directory into the Moodle 2.0 MBZ format. To test it now, modify the process_choice() method so that it just dumps the $data:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function process_choice($data) {&lt;br /&gt;
    print_object($data); // DONOTCOMMIT&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and run the convert.php. If you are lucky enough, you should see an array dumped for each choice instance defined in moodle.xml file. Also look at $CFG-&amp;gt;dataroot/temp/backup/ - you should see that the &#039;refcourse&#039; now contains the converted version of the backup and the original 1.9 should be left there for the reference, too. Do not continue unless this works for you.&lt;br /&gt;
&lt;br /&gt;
=== Data structure transformations ===&lt;br /&gt;
&lt;br /&gt;
As you can from the print_object() output, the process_choice() method is passed the data contained in the corresponding &amp;lt;MOD&amp;gt;...&amp;lt;/MOD&amp;gt; part of the moodle.xml file. We know that we need to rename fields &#039;&#039;text&#039;&#039; and &#039;&#039;format&#039;&#039;, add a new field &#039;&#039;completionsubmit&#039;&#039; and drop the field &#039;&#039;modtype&#039;&#039; (that one was already used to expand the XML path so that it looks as if the moodle.xml defined the data inside &amp;lt;MOD&amp;gt;&amp;lt;CHOICE&amp;gt;...&amp;lt;/CHOICE&amp;gt;&amp;lt;/MOD&amp;gt;). These transformations are pretty common and the converter can do them on behalf of us.&lt;br /&gt;
&lt;br /&gt;
You can provide so called &#039;&#039;recipes&#039;&#039; that will be applied to the element data before they are dispatched to the proces_xxx() methods. These recipes are used to &amp;quot;pre-cook&amp;quot; the raw data from moodle.xml. In fact, one such recipe has been already applied by default - converting the tag names to lower case. Three other types of recipes are supported at the moment: to add new fields, to rename fields and to drop fields. All you need to do is to declare what recipes and in what order should be applied on the parsed data. You can do so by adding the third parameter to the constructor of convert_path instances in get_paths() method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function get_paths() {&lt;br /&gt;
    return array(&lt;br /&gt;
        new convert_path(&lt;br /&gt;
            &#039;choice&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE&#039;,&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;renamefields&#039; =&amp;gt; array(&lt;br /&gt;
                    &#039;text&#039; =&amp;gt; &#039;intro&#039;,&lt;br /&gt;
                    &#039;format&#039; =&amp;gt; &#039;introformat&#039;,&lt;br /&gt;
                ),&lt;br /&gt;
                &#039;newfields&#039; =&amp;gt; array(&lt;br /&gt;
                    &#039;completionsubmit&#039; =&amp;gt; 0,&lt;br /&gt;
                ),&lt;br /&gt;
                &#039;dropfields&#039; =&amp;gt; array(&lt;br /&gt;
                    &#039;modtype&#039;&lt;br /&gt;
                ),&lt;br /&gt;
            )&lt;br /&gt;
        ),&lt;br /&gt;
        new convert_path(&#039;choice_option&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE/OPTIONS/OPTION&#039;),&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the third parameter is an associative array. The keys of the array are the names of the recipes. The &#039;&#039;renamefields&#039;&#039; recipe will be applied first and will rename &#039;&#039;text&#039;&#039; to &#039;&#039;intro&#039;&#039; and &#039;&#039;format&#039;&#039; to &#039;&#039;introformat&#039;&#039;. The &#039;&#039;newfields&#039;&#039; recipe will add a new field &#039;&#039;completionsubmit&#039;&#039; with the value set to 0. And finally, the &#039;&#039;dropfields&#039;&#039; recipe will delete the field &#039;&#039;modtype&#039;&#039; from the data.&lt;br /&gt;
&lt;br /&gt;
In case you would need to know how the data looked like before applying the recipes, your process_xxx() method can get them via its second parameter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
public function process_choice($data, $raw) {&lt;br /&gt;
    print_object($data); // DONOTCOMMIT&lt;br /&gt;
    print_object($raw); // DONOTCOMMIT&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may be required if, for example, you need to calculate a value of a new field from the value of some field that was dropped by the recipe.&lt;br /&gt;
&lt;br /&gt;
=== Writing the transformed data into the new XML file ===&lt;br /&gt;
&lt;br /&gt;
Now we have the choice data transformed and passed to process_choice() method and we can write them into the new XML file in the MBZ format directory. As you know, the module instance data are saved in a file like activities/choice_x/choice.xml where x is the course moduleid of our current instance (note that we do not know this cmid yet). Following the principle &amp;quot;write data as soon as possible&amp;quot;, let us go and write them into the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE&lt;br /&gt;
 * data available&lt;br /&gt;
 */&lt;br /&gt;
public function process_choice($data) {&lt;br /&gt;
&lt;br /&gt;
    // get the course module id and context id&lt;br /&gt;
    $instanceid = $data[&#039;id&#039;];&lt;br /&gt;
    $cminfo     = $this-&amp;gt;get_cminfo($instanceid);&lt;br /&gt;
    $moduleid   = $cminfo[&#039;id&#039;];&lt;br /&gt;
    $contextid  = $this-&amp;gt;converter-&amp;gt;get_contextid(CONTEXT_MODULE, $moduleid);&lt;br /&gt;
&lt;br /&gt;
    // we now have all information needed to start writing into the file&lt;br /&gt;
    $this-&amp;gt;open_xml_writer(&amp;quot;activities/choice_{$moduleid}/choice.xml&amp;quot;);&lt;br /&gt;
    $this-&amp;gt;xmlwriter-&amp;gt;begin_tag(&#039;activity&#039;, array(&#039;id&#039; =&amp;gt; $instanceid, &#039;moduleid&#039; =&amp;gt; $moduleid,&lt;br /&gt;
        &#039;modulename&#039; =&amp;gt; &#039;choice&#039;, &#039;contextid&#039; =&amp;gt; $contextid));&lt;br /&gt;
    $this-&amp;gt;xmlwriter-&amp;gt;begin_tag(&#039;choice&#039;, array(&#039;id&#039; =&amp;gt; $instanceid));&lt;br /&gt;
&lt;br /&gt;
    unset($data[&#039;id&#039;]); // we already write it as attribute, do not repeat it as child element&lt;br /&gt;
    foreach ($data as $field =&amp;gt; $value) {&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;full_tag($field, $value);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let us look closely on what&#039;s going on here. At the top, we prepare the values needed for attributes of the &amp;lt;activity&amp;gt; tag that is the root element of the file. Our parent class defines a method get_cminfo() that returns a structure containing the needed cmid for our instance. The get_contextid() method is a bit more tricky. In Moodle 1.9 backup files, there is no context information stored at all. But Moodle 2.0 format contains it. So the converter must actually generate fictive context ids for various levels (course, modules, blocks, ...) as if they were stored in moodle.xml.&lt;br /&gt;
&lt;br /&gt;
In the next step, we open a new XML file for writing. Then we use xml_writer&#039;s method begin_tag() to dump the first lines of the file. Then, in the foreach loop, we write all cooked data into the opened file. Note that we leave the file open so that other methods in our class can continue adding their own data to it.&lt;br /&gt;
&lt;br /&gt;
The process_xxx() method should return the $data if it modifies them (so they could be used later by on_choice_end() method, if it was needed). But as long as we do not do any other transformation, we do not return anything. In that case, our $this-&amp;gt;converter stores just the cooked data for eventual later processing.&lt;br /&gt;
&lt;br /&gt;
=== On-path-start and on-path-end events ===&lt;br /&gt;
&lt;br /&gt;
So far we&#039;ve worked with the method process_choice() that is executed every time we have the attached element&#039;s data available. For each registered path, two more methods are supported in our handler. Assuming that &#039;xxx&#039; is the alias for the path we declared in get_paths(), the methods on_xxx_start() and on_xxx_end() will be executed every time we reach the opening tag and closing tag of that path, respectively.&lt;br /&gt;
&lt;br /&gt;
The on_xxx_start() does not accept any parameters and it is executed when the opening element for the given path is reached by the parser. The on_xxx_end() may accept one array $data that contains the element&#039;s data processed previously by the process_xxx() method. Typical usage for these two handlers is to write wrapping tags into the target XML file. Let us demonstrate this case.&lt;br /&gt;
&lt;br /&gt;
Let us register yet another path in the get_paths() method (note the plural - choice_options)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
new convert_path(&#039;choice_options&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE/OPTIONS&#039;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the &amp;lt;OPTIONS&amp;gt; itself does not contain any data (leaves in the XML tree), it is just a wrapper for the nested &amp;lt;OPTION&amp;gt; elements. So there is no point of having process_choice_options() method because it would be never executed. However we register this path so that we can declare two event listeners for it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This is executed when the parser reaches the &amp;lt;OPTIONS&amp;gt; opening element&lt;br /&gt;
 */&lt;br /&gt;
public function on_choice_options_start() {&lt;br /&gt;
    $this-&amp;gt;xmlwriter-&amp;gt;begin_tag(&#039;options&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This is executed when the parser reaches the closing &amp;lt;/OPTIONS&amp;gt; element&lt;br /&gt;
 */&lt;br /&gt;
public function on_choice_options_end() {&lt;br /&gt;
    $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;options&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, we use the on-start and on-end event listeners here to generate the wrapping &amp;lt;options&amp;gt;&amp;lt;/options&amp;gt; tag pair. And the next step is just to make sure that the inner &amp;lt;option&amp;gt;...&amp;lt;/option&amp;gt; data are written into the file, too.&lt;br /&gt;
&lt;br /&gt;
=== Writing a complete tree-ish structure into the XML file in one step ===&lt;br /&gt;
&lt;br /&gt;
As the parser continues parsing the moodle.xml file, our handler&#039;s method process_choice_option() is called once there are data for a single &amp;lt;OPTION&amp;gt;...&amp;lt;/OPTION&amp;gt; element available (because we registered it as a path we are interested in). In this case, the situation is much much simpler. There are no transformations needed (but converting tags to lower case and it is done automatically). Therefore we we can write the whole array including the closing &amp;lt;/option&amp;gt; tag. In such case there is a nice helper method available:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/CHOICE/OPTIONS/OPTION&lt;br /&gt;
 * data available&lt;br /&gt;
 */&lt;br /&gt;
public function process_choice_option($data) {&lt;br /&gt;
    $this-&amp;gt;write_xml(&#039;option&#039;, $data, array(&#039;/option/id&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This write_xml() method writes the given $data tree into the &amp;lt;option&amp;gt;...&amp;lt;/option&amp;gt; element and $data-&amp;gt;id will be written as the option&#039;s attribute instead of a child element.&lt;br /&gt;
&lt;br /&gt;
=== Finishing the job ===&lt;br /&gt;
&lt;br /&gt;
When all options are written, we need to generate the closing tags, close the file and release our xml writer. For this we can use the on-path-end event listening method again. This one is executed as the parsers reaches the closing &amp;lt;/MOD&amp;gt; tag in moodle.xml (or rather think of it as if it reached the closing &amp;lt;/CHOICE&amp;gt; tag in that virtual &amp;lt;/CHOICE&amp;gt;&amp;lt;/MOD&amp;gt; path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This is executed when we reach the closing &amp;lt;/MOD&amp;gt; tag of our &#039;choice&#039; path&lt;br /&gt;
 */&lt;br /&gt;
public function on_choice_end() {&lt;br /&gt;
    // close choice.xml&lt;br /&gt;
    $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;choice&#039;);&lt;br /&gt;
    $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;activity&#039;);&lt;br /&gt;
    $this-&amp;gt;close_xml_writer();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this on_xxx_end() function can take a parameter $data that would contain the data returned previously by process_xxx(). If the processing method does not return anything, just the cooked raw data are available to the on_xxx_end() method.&lt;br /&gt;
&lt;br /&gt;
And we are done! Execute the convert.php again and you shall find the choice.xml file converted correctly there. Was easy, heh? :-)&lt;br /&gt;
&lt;br /&gt;
=== Important notes ===&lt;br /&gt;
&lt;br /&gt;
* Note that you can&#039;t use on_choice_start() event listening method for the root &amp;lt;MOD&amp;gt; element itself. There is a reason for that described in the phpdoc of the dispatching moodle1 methods, if you are interested. Just live with that that the process_choice() in our example is the first executed entry point in your class.&lt;br /&gt;
* Note that in our case, there is actually no need to use on_choice_options_start() and on_choice_options_end() methods. We could simply write the opening &amp;lt;options&amp;gt; at the end of process_choice() and then the closing &amp;lt;/options&amp;gt; at the top of on_choice_end(). We describe the start/end listeners here to demonstrate the feature mainly. And also, some may find the resulting code cleaner.&lt;br /&gt;
&lt;br /&gt;
== Files migration ==&lt;br /&gt;
&lt;br /&gt;
While studying the upgrade steps in db/upgrade.php, you might notice that your module needs to migrate its files into the new [[File API|file API]] framework. Typical cases are for example forum posts attachments, submitted files in the assignment etc. You module converter has to apply the similar logic, pretending that the final XML files were created in a virtual 2.0 site with the files already migrated.&lt;br /&gt;
&lt;br /&gt;
=== Where files can be stored in the 1.9 backup ZIP file ===&lt;br /&gt;
&lt;br /&gt;
* All the course files are copied into the &#039;&#039;course_files&#039;&#039; folder within the ZIP, see backup_copy_course_files().&lt;br /&gt;
* All the site files are copies into the &#039;&#039;site_files&#039;&#039; folder, if the user used this feature, see backup_copy_site_files().&lt;br /&gt;
* Needed user files and group files are copied into &#039;&#039;user_files&#039;&#039; and &#039;&#039;group_files&#039;&#039; folders, respectively. See backup_copy_user_files() and backup_copy_group_files().&lt;br /&gt;
* Module specific files (forum posts attachments, ...) as copied by the modules themselves in their backuplib, See for example backup_workshop_files().&lt;br /&gt;
&lt;br /&gt;
=== How files are stored in the 2.0 backup MBZ file ===&lt;br /&gt;
&lt;br /&gt;
The files related information is stored at several places in the MBZ file:&lt;br /&gt;
&lt;br /&gt;
* The /files folder is a pool for all the needed files. It is a [http://en.wikipedia.org/wiki/Content-addressable_storage content-addressable storage] as the file name is SHA1 hash of the file contents and files are grouped into directories according the first two characters of their name.&lt;br /&gt;
* The /files.xml file contains records from the mdl_files table where each file usage is described. This is similar to hard-linking mechanism in file systems. Note that the number of files listed in files.xml is greater than the number of physical files in the /files folder for two reasons: (1) the directories themselves are listed in files.xml (see the filename &#039;.&#039;) and (2) one physical file in the pool can be referenced from two different places in files.xml&lt;br /&gt;
* Every module has to declare the files it needs in its inforef.xml files (among other references).&lt;br /&gt;
&lt;br /&gt;
So to convert your module files, you must make sure that the files are copied into the pool, are listed in the common files.xml and are correctly referenced in your inforef.xml file. The files.xml file is generated automatically by one of the moodle1_converter core handlers but your module must write your inforef.xml yourself. To do so, you should always use the moodle1_file_manager instance.&lt;br /&gt;
&lt;br /&gt;
=== Files migration manager ===&lt;br /&gt;
&lt;br /&gt;
The easiest way to migrate your files and get their ids for dumping them into inforef.xml is to use one instance of moodle1_file_manager per each module instance you convert. Every instance of the file manager keeps track of file ids it creates. The file manager can be seen as an object with several public properties that represent the values of the records in files.xml file. These properties can be set either implicitly via the factory method (that passes them to the manager constructor) or explicitly. The file manager has two public methods: migrate_file() used to migrate one particular file and migrate_directory() to migrate whole directory of files (including subdirectories).&lt;br /&gt;
&lt;br /&gt;
Let us look at a particular example of how the Workshop module uses the file manager.&lt;br /&gt;
&lt;br /&gt;
=== Use case 1: Migrating workshop submission attachments ===&lt;br /&gt;
&lt;br /&gt;
Workshop module stores submission attachments in files like /moddata/workshop/xxx/filename.ext where &#039;xxx&#039; is the submission id. Multiple files are allowed there. During the migration, these files must be transformed into records with the:&lt;br /&gt;
&lt;br /&gt;
* contextid set to the workshop course module context&lt;br /&gt;
* component set to &#039;mod_workshop&#039;&lt;br /&gt;
* filearea set to &#039;submission_attachment&#039;&lt;br /&gt;
* itemid set to the submission id&lt;br /&gt;
* userid set to the id of the user who submitted the file&lt;br /&gt;
* filename set to the original file name&lt;br /&gt;
* filepath set to &#039;/&#039; (all files are in the root directory in the given filearea/itemid&lt;br /&gt;
&lt;br /&gt;
It is obvious that all the submission file records in the given workshop instance share the same context, component and filearea. For each submission, the itemid and userid must be set based on the data in &amp;lt;SUBMISSION&amp;gt; element.&lt;br /&gt;
&lt;br /&gt;
Let us create a new instance of the file manager at the bottom of the process_workshop() method that is attached to the root &amp;lt;MOD&amp;gt; element of one workshop instance (the following code shows just the important parts of the whole class):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class moodle1_mod_workshop_handler extends moodle1_mod_handler {&lt;br /&gt;
&lt;br /&gt;
    /** @var array in-memory cache for the course module information for the current workshop  */&lt;br /&gt;
    protected $currentcminfo = null;&lt;br /&gt;
&lt;br /&gt;
    /** @var moodle1_file_manager instance for the current workshop */&lt;br /&gt;
    protected $fileman = null;&lt;br /&gt;
&lt;br /&gt;
    public function get_paths() {&lt;br /&gt;
        return array(&lt;br /&gt;
            new convert_path(&#039;workshop&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP&#039;),&lt;br /&gt;
            new convert_path(&#039;workshop_submissions&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP/SUBMISSIONS&#039;),&lt;br /&gt;
            new convert_path(&#039;workshop_submission&#039;, &#039;/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP/SUBMISSIONS/SUBMISSION&#039;)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function process_workshop($data, $raw) {&lt;br /&gt;
        $instanceid          = $data[&#039;id&#039;];&lt;br /&gt;
        $this-&amp;gt;currentcminfo = $this-&amp;gt;get_cminfo($instanceid);&lt;br /&gt;
        $moduleid            = $this-&amp;gt;currentcminfo[&#039;id&#039;];&lt;br /&gt;
        $contextid           = $this-&amp;gt;converter-&amp;gt;get_contextid(CONTEXT_MODULE, $moduleid);&lt;br /&gt;
&lt;br /&gt;
        // prepare the file manager for this instance&lt;br /&gt;
        $this-&amp;gt;fileman = $this-&amp;gt;converter-&amp;gt;get_file_manager($contextid, &#039;mod_workshop&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function on_workshop_submissions_start() {&lt;br /&gt;
        $this-&amp;gt;fileman-&amp;gt;filearea = &#039;submission_attachment&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function process_workshop_submission($data) {&lt;br /&gt;
        // migrate submission attachments&lt;br /&gt;
        $this-&amp;gt;fileman-&amp;gt;itemid = $data[&#039;id&#039;];&lt;br /&gt;
        $this-&amp;gt;fileman-&amp;gt;userid = $data[&#039;userid&#039;];&lt;br /&gt;
        $this-&amp;gt;fileman-&amp;gt;migrate_directory(&#039;moddata/workshop/&#039;.$data[&#039;id&#039;]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The main job happens in process_workshop_submission() method. When it is executed, $this-&amp;gt;fileman is correctly configured to migrate files into the correct context, component and filearea. If the directory moddata/workshop/xxx/ exists within the backup for the current submission, we set the relevant properties of the fileman and ask it to migrate all files in that directory.&lt;br /&gt;
&lt;br /&gt;
Note that because we migrate files to the &#039;submission_attachment&#039; filearea only, we could actually set it via get_file_manager() and get rid of the listener of &amp;lt;SUBMISSIONS&amp;gt; completely. The code above should illustrate how you can change the manager&#039;s properties to desired values as the parser goes down the moodle.xml file. Usually you will set at least contextid and the component name in the factory method get_file_manager() because those will not change. Other properties are set to correct values as soon as they are available.&lt;br /&gt;
&lt;br /&gt;
The last step is to generate inforef.xml where we annotate all migrated files as being referenced by this workshop instance.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    public function on_workshop_end() {&lt;br /&gt;
        // close workshop.xml&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;workshop&#039;);&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;activity&#039;);&lt;br /&gt;
        $this-&amp;gt;close_xml_writer();&lt;br /&gt;
&lt;br /&gt;
        // write inforef.xml&lt;br /&gt;
        $moduleid = $this-&amp;gt;currentcminfo[&#039;id&#039;];&lt;br /&gt;
        $this-&amp;gt;open_xml_writer(&amp;quot;activities/workshop_{$moduleid}/inforef.xml&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;begin_tag(&#039;inforef&#039;);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;begin_tag(&#039;fileref&#039;);&lt;br /&gt;
        foreach ($this-&amp;gt;fileman-&amp;gt;get_fileids() as $fileid) {&lt;br /&gt;
            $this-&amp;gt;write_xml(&#039;file&#039;, array(&#039;id&#039; =&amp;gt; $fileid));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;fileref&#039;);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;xmlwriter-&amp;gt;end_tag(&#039;inforef&#039;);&lt;br /&gt;
        $this-&amp;gt;close_xml_writer();&lt;br /&gt;
&lt;br /&gt;
        // get ready for the next instance&lt;br /&gt;
        $this-&amp;gt;currentworkshop = null;&lt;br /&gt;
        $this-&amp;gt;currentcminfo   = null;&lt;br /&gt;
        $this-&amp;gt;newelementids   = array();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use the file manager&#039;s method get_fileids() that returns the list of all files it has ever converted. And because we create new file manager instance for every single workshop instance, the list is exactly what must be put into inforef.xml.&lt;br /&gt;
&lt;br /&gt;
Note that inforef.xml will contain more data later - the list of annotated users, roles, scales and other items used by the given instance is used there.&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Available_update_notifications&amp;diff=64535</id>
		<title>Available update notifications</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Available_update_notifications&amp;diff=64535"/>
		<updated>2025-02-10T07:44:41Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Available update notifications&lt;br /&gt;
|state = Completed - code integrated into Moodle 2.3&lt;br /&gt;
|tracker = MDL-20438&lt;br /&gt;
|discussion = [[Talk:Available update notifications|Talk page]]&lt;br /&gt;
|assignee = [[User:David Mudrak|David Mudrak]], Eloy Lafuente&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
== Goals and milestones ==&lt;br /&gt;
&lt;br /&gt;
Keeping a Moodle site up-to-date is the primary way of keeping it secure. We should encourage admins to update their sites to the most recent stable version on a regular basis. As a first step, for Moodle 2.3, we will implement a notification infrastructure to:&lt;br /&gt;
&lt;br /&gt;
* notify admins about Moodle core updates available for their site; and&lt;br /&gt;
* notify admins about available updates for the contributed plugins installed on their site.&lt;br /&gt;
&lt;br /&gt;
Notifications will be displayed at the Admin notifications page and Plugins overview page. In their messaging preferences, admins will be able to set up notifications to be sent by email, Jabber, etc. (using standard [[Message_API|messaging]] features).&lt;br /&gt;
&lt;br /&gt;
== Scrolls of Wisdom ==&lt;br /&gt;
&lt;br /&gt;
Prior to displaying these notifications (and eventually sending them in email/message via the inbuilt messaging system) we need to fetch the relevant information from some authoritative source. There are two places with the required &amp;quot;knowledge&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
; download.moodle.org : The [http://download.moodle.org/ Download site] is the place where standard Moodle packages are announced and published. This is the place where Moodle HQ officially declare what is the most recent version of Moodle core available (for each supported branch).&lt;br /&gt;
; moodle.org/plugins : The [http://moodle.org/plugins Plugins directory] is the place where contributed plugins are registered. Although contributed extensions can be published and announced anywhere, Moodle HQ provide notification support for plugins registered at the Plugins directory only.  : This is definitely the new Plugins repository at .&lt;br /&gt;
&lt;br /&gt;
Even though there are these two authoritative sources, Moodle sites access a single URL when fetching the information about available updates. See the communication protocol described below for details.&lt;br /&gt;
&lt;br /&gt;
From now on, &amp;quot;the client&amp;quot; in the text represents the local Moodle site where the information about available update should be displayed. &amp;quot;The remote site&amp;quot; represents a site maintained by Moodle HQ where the information about available update is defined. Clients read from the remote site and display eventual notifications to their admins.&lt;br /&gt;
&lt;br /&gt;
== One Click to Rule Then All ==&lt;br /&gt;
&lt;br /&gt;
From the user&#039;s perspective, obtaining the information about available updates (and actually obtaining those updates themselves in the future) should be as simple as clicking a button, or simpler (that is the check is done automatically by cron every now and then). But it should be clearly documented what&#039;s going on behind the scene and what information about the client is sent to the remote site during the request.&lt;br /&gt;
&lt;br /&gt;
The privacy aspect of this project was discussed. There was a proposal to gather overview stats about the client during the request. But there was also an objection that this feature should be specific for hub subscription exclusively with an easy and single place to opt-out. At the end it was decided that:&lt;br /&gt;
&lt;br /&gt;
* The client must provide just basic information about itself - the installed Moodle version and the branch.&lt;br /&gt;
* If the client wants to receive the information about available updates for additional (non-standard, contributed) plugins, it must provide their list together with their current versions.&lt;br /&gt;
* The remote site uses submitted data to return just the relevant update information. If the client declares it is a Moodle 2.3 site with the mod_foo and mod_bar extensions installed, the remote site returns the information about the most recent version at MOODLE_23_STABLE, MOODLE_24_STABLE and any other higher branch, including master. The information about the most recent versions of mod_foo and mod_bar for the current MOODLE_23_STABLE branch (if there are such versions) is returned, too.&lt;br /&gt;
* As a part of each response, the remote site returns a special hash-like value called &amp;quot;ticket&amp;quot;. The client should use the ticket during the next request. This mechanism helps Moodle HQ to match all requests coming from a single client even without using any sensitive information that would identify the site. This way, Moodle HQ can monitor the distribution of Moodle versions and deployed plugins while fully respecting the anonymous access to the update notification service.&lt;br /&gt;
&lt;br /&gt;
== Communication protocol, or There and Back Again ==&lt;br /&gt;
&lt;br /&gt;
This section describes how a Moodle site as a client can fetch the information from the remote site.&lt;br /&gt;
&lt;br /&gt;
=== Available Moodle update ===&lt;br /&gt;
&lt;br /&gt;
[[image:uml-updates-core.png|400px|thumb|left|UML sequence diagram - Checking for the available updates of Moodle core]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* A: The admin visits the Notifications page&lt;br /&gt;
* B: During the page rendering, the available_update_checker class is called, requesting the information for the &amp;quot;core&amp;quot; component.&lt;br /&gt;
* C: The checker looks into the local storage/cache (currently implemented using the config_plugins table) for the available update info.&lt;br /&gt;
* D: The available update info is returned to the caller script. It is basically a data object that holds some useful properties like version, release (build) and maturity of Moodle code available at the remote site.&lt;br /&gt;
* E: If the version available at the remote site is newer than the one currently installed, inform the admin. Admins can configure what maturity level the updates must have to be informed about (eg &amp;quot;Inform me about stable releases only&amp;quot;) and whether they want to be informed about weekly builds, too.&lt;br /&gt;
* F: The admin presses the button &amp;quot;Check for update now&amp;quot; (eventually a cronjob to do so is executed, the procedure is the same).&lt;br /&gt;
* G: The checker&#039;s method fetch() is called&lt;br /&gt;
* H: Internally, the checker class prepares the request URL to contain the currently installed Moodle version, branch and the list of installed plugins. It makes the HTTP POST request to the remote site script &#039;&#039;&#039;http://download.moodle.org/api/1.0/updates.php&#039;&#039;&#039;&lt;br /&gt;
* J: The remote site returns requested data in a form of JSON encoded structure.&lt;br /&gt;
* K: The checker class stores the response in the local storage for later usage&lt;br /&gt;
* L: The browser is redirected back to the screen with the button. GOTO A.&lt;br /&gt;
&lt;br /&gt;
=== Available plugin updates ===&lt;br /&gt;
&lt;br /&gt;
[[image:uml-updates-plugins.png|700px|thumb|left|UML sequence diagram - Checking for the available updates of Moodle plugins]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The mechanism is the same from the client&#039;s point of view. The remote site runs its own cron jobs to fetch and populate required data from both sources and make them ready to be served.&lt;br /&gt;
&lt;br /&gt;
=== Example response format ===&lt;br /&gt;
&lt;br /&gt;
    $data = array(&lt;br /&gt;
        &#039;status&#039; =&amp;gt; &#039;OK&#039;, // the constant &#039;OK&#039; is checked by the client&lt;br /&gt;
        &#039;provider&#039; =&amp;gt; &#039;http://download.moodle.org/api/1.0/updates.php&#039;, // our URL that prepared these data&lt;br /&gt;
        &#039;apiver&#039; =&amp;gt; &#039;1.0&#039;, // API version determines the format of the response&lt;br /&gt;
        &#039;timegenerated&#039; =&amp;gt; time(), // our timestamp of when the data were populated and sent back&lt;br /&gt;
        &#039;forbranch&#039; =&amp;gt; &#039;2.3&#039;, // the caller&#039;s major version they provided in the request&lt;br /&gt;
        &#039;forversion&#039; =&amp;gt; &#039;2012031500.00&#039;, // the caller&#039;s version they provided in the request&lt;br /&gt;
        &#039;ticket&#039; =&amp;gt; $newticket, // a value that the client should pass via the &#039;ticket&#039; param during the next request&lt;br /&gt;
        &#039;updates&#039; =&amp;gt; array( // list of available updates for the caller (based on their version provided in the request)&lt;br /&gt;
            &#039;core&#039; =&amp;gt; array( // Moodle core updates. eg for a 2.3 client it would return all stable 2.3.x, 2.4.y, 2.5.z etc&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2012031500.04,&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;2.3dev (Build: 20121201)&#039;,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 200, // one of the MATURITY_xxx constants&lt;br /&gt;
                    &#039;url&#039; =&amp;gt; &#039;http://download.moodle.org/&#039;, // general URL to visit and know more about the component&lt;br /&gt;
                    &#039;download&#039; =&amp;gt; &#039;http://download.moodle.org/download.php/MOODLE_23_STABLE/moodle-2.3.3-latest.zip&#039;, // URL to get the ZIP&lt;br /&gt;
                ),&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2012120100.06,&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;2.3dev (Build: 20121201)&#039;,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 150, // one of the MATURITY_RC constants&lt;br /&gt;
                    &#039;url&#039; =&amp;gt; &#039;http://download.moodle.org/&#039;,&lt;br /&gt;
                    &#039;download&#039; =&amp;gt; &#039;http://download.moodle.org/download.php/MOODLE_24_STABLE/moodle-2.4.0-latest.zip&#039;,&lt;br /&gt;
                ),&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2012120804,&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;2.3dev (Build: 20121208)&#039;,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 50, // one of the MATURITY_xxx constants&lt;br /&gt;
                    &#039;url&#039; =&amp;gt; &#039;http://download.moodle.org/&#039;,&lt;br /&gt;
                    &#039;download&#039; =&amp;gt; &#039;http://download.moodle.org/download.php/master/moodle-2.5-dev.zip&#039;,&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;local_moodlecheck&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    // info from the plugin&#039;s version.php, just &#039;version&#039; is mandatory&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2012011000,&lt;br /&gt;
                    &#039;requires&#039; =&amp;gt; 2010112400,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 200, // {@link MATURITY_STABLE}&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;1.0&#039;,&lt;br /&gt;
                    &#039;url&#039; =&amp;gt; &#039;http://moodle.org/plugins/&#039;,&lt;br /&gt;
                    &#039;download&#039; =&amp;gt; &#039;http://moodle.org/plugins/download.php&#039;,&lt;br /&gt;
                ),&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2012091501,&lt;br /&gt;
                    &#039;requires&#039; =&amp;gt; 2010112400,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 150, // {@link MATURITY_STABLE}&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;1.1 RC1&#039;,&lt;br /&gt;
                    &#039;url&#039; =&amp;gt; &#039;http://moodle.org/plugins/&#039;,&lt;br /&gt;
                    &#039;download&#039; =&amp;gt; &#039;http://moodle.org/plugins/download.php&#039;,&lt;br /&gt;
                ),&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2012120100,&lt;br /&gt;
                    &#039;requires&#039; =&amp;gt; 2010112400,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 50, // {@link MATURITY_STABLE}&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;1.2 dev&#039;,&lt;br /&gt;
                    &#039;url&#039; =&amp;gt; &#039;http://moodle.org/plugins/&#039;,&lt;br /&gt;
                    &#039;download&#039; =&amp;gt; &#039;http://moodle.org/plugins/download.php&#039;,&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;qtype_oumultiresponse&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;version&#039; =&amp;gt; 2011051200,&lt;br /&gt;
                    &#039;requires&#039; =&amp;gt; 2011070100,&lt;br /&gt;
                    &#039;maturity&#039; =&amp;gt; 200, // {@link MATURITY_STABLE}&lt;br /&gt;
                    &#039;release&#039; =&amp;gt; &#039;1.0&#039;,&lt;br /&gt;
                    &#039;dependencies&#039; =&amp;gt; array(&lt;br /&gt;
                        &#039;qtype_multichoice&#039; =&amp;gt; &#039;any&#039;, // {@link ANY_VERSION}&lt;br /&gt;
                    ),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
        ),&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
== Discussion ==&lt;br /&gt;
&lt;br /&gt;
This section contains some leftover notes from the previous versions of this spec to illustrate the background and considered aspects of the design.&lt;br /&gt;
&lt;br /&gt;
Originally there have been several suggestions of how the information about the available updates would be transferred from primary sources to target sites.&lt;br /&gt;
&lt;br /&gt;
; Generated XML files : This was proposed by Petr in October 2009 and is described at the [[Upgrade notification]] page. The format itself (XML) does not matter much and can be replaced by JSON or another format. The pros of this approach is that these files can be generated by a cronjob and cached to improve performance by reducing queries.&lt;br /&gt;
; Using the current component_installer : This overlaps the previous approach. As Eloy pointed out, correctly, we already have a system like this in Moodle core. We use it for timezones and language packs at the moment. The pros of this is that we already use it and it seems to work pretty well.&lt;br /&gt;
; Using heavy-weight web service : This project seems to be a good opportunity for the new [[Web services|WS]] framework we have. The source of information would expose the functionality via the WS API. REST/JSON format seems to be the way to go. See [[Specification - create a public web service server]].&lt;br /&gt;
; Using light-weight web service : As we do not need to cope with the access control here (and need something really cheap in terms of resources and performance), there is actually no need to use the underlying WS subsystem. The service can be produced by a simple script. There is already this approach used at http://lang.moodle.org/local/amos/rest/greylist?format=csv (see [https://github.com/moodlehq/moodle-local_amos/commit/a746fc07edce3d8def644cfab948575b10225448 this commit] to see how it is implemented).&lt;br /&gt;
; Combining with current [[:en:Site_registration|site registration]] system : The registration system is used to gather information about sites for statistical purposes. It could be enhanced to return information about current versions.&lt;br /&gt;
&lt;br /&gt;
It is also wise to consider extending the system in the future. We should come up with a solution that is capable of not only providing a list of available updates, but also delivers the source code packages themselves.&lt;br /&gt;
&lt;br /&gt;
=== Gathering statistical information during an update check ===&lt;br /&gt;
&lt;br /&gt;
There is potential to gather information about the Moodle version and plugin versions related to a site.&lt;br /&gt;
&lt;br /&gt;
At the moment, plugin downloads and page views is the only measure of plugin popularity we are capturing. If we can gather real information about plugins installed on sites and the number of instances in use, we can build up a realistic picture of the popularity of plugins, which can be returned as feedback to plugin developers and potential users.&lt;br /&gt;
&lt;br /&gt;
Moodle version information is shared via [[:en:Site_registration|site registration]], however, not all sites register. Perhaps offering this service with a prerequisite of registering will encourage more admins to register, leading to a clearer picture of Moodle use.&lt;br /&gt;
&lt;br /&gt;
The information gathered by this system could be seen as confidential, so it would be necessary to include an opt in/out mechanism similar to, or combined with, the current site registration. If this update notification system is to be constructed separately to the registration system, it may still be possible to gather information about Moodle and plugin versions during a passive update check. If the site transmits a list of plugins and versions, this could be paired to the sender&#039;s IP address and retained semi-anonymously.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Automatic updates deployment]] project (since Moodle 2.4).&lt;br /&gt;
* [[On-click add-on installation]] project (since Moodle 2.5).&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Automatic_updates_deployment&amp;diff=64534</id>
		<title>Automatic updates deployment</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Automatic_updates_deployment&amp;diff=64534"/>
		<updated>2025-02-10T07:43:39Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Automatic updates deployment&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-35238 and MDL-35239&lt;br /&gt;
|discussion = [http://moodle.org/mod/forum/discuss.php?d=211936 Automatic updates deployment]&lt;br /&gt;
|assignee = [[User:David Mudrak|David Mudrak]], Eloy Lafuente&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.4}}&lt;br /&gt;
&lt;br /&gt;
== Use cases ==&lt;br /&gt;
&lt;br /&gt;
[[Image:sue.png|left|Sue the admin]] Meet Sue, a Moodle administrator. She runs her Moodle at a cheap web hosting company where she gets an FTP access only (and some basic web tool to administer one SQL database). No shell access, no way to use Git etc. She never modifies source codes manually. And she likes how Wordpress deals with updates.&lt;br /&gt;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Use case 1 ===&lt;br /&gt;
&lt;br /&gt;
* Sue uploads a new minor Moodle version and executes the upgrade (say from 2.4.0 to 2.4.1)&lt;br /&gt;
* At the &amp;quot;Plugins check&amp;quot; screen, there is an info about some available updates. Prior to continuing with the Moodle upgrade, Sue is recommended to deploy new versions for these plugins.&lt;br /&gt;
* So she keeps all available plugin updates selected and clicks &amp;quot;Update all selected plugins&amp;quot;&lt;br /&gt;
* New versions of selected plugins are downloaded and deployed into wwwroot, replacing the current content (some progress bars and info would be nice to have).&lt;br /&gt;
* The &amp;quot;Plugins check&amp;quot; screen is reload again. Now no available updates are reported - those plugins that were reported before are now marked as &amp;quot;To be upgraded&amp;quot;&lt;br /&gt;
* Sue presses the &amp;quot;Upgrade Moodle database now&amp;quot; button. Both Moodle core and all plugins are updated.&lt;br /&gt;
&lt;br /&gt;
=== Use case 2 ===&lt;br /&gt;
&lt;br /&gt;
* Sue wants to install a contributed extension into her Moodle.&lt;br /&gt;
* Using a new admin tool, she can browse the list of available plugins. She gets the basic information about plugins and can read more about them using a direct link to http://moodle.org/plugins registry.&lt;br /&gt;
* When she finds the plugin she is looking for, she presses the button &amp;quot;Download&amp;quot;.&lt;br /&gt;
* At the next screen, confirms the source URL and the target location. She presses the &amp;quot;Download&amp;quot; button again.&lt;br /&gt;
* The ZIP file with the plugin is downloaded. Its MD5 content hash is compared with the expected value. The ZIP is unpacked into the correct location inside wwwroot.&lt;br /&gt;
* The browser is redirected to the /admin so the normal upgrade continues as if Sue uploaded the plugin herself.&lt;br /&gt;
&lt;br /&gt;
=== Use case 3 ===&lt;br /&gt;
&lt;br /&gt;
* On Friday morning, Sue gets a regular email generated by her site that a new weekly build is available for her Moodle.&lt;br /&gt;
* She likes her site being up-to-date because she knows that up-to-date code is essential for the site security.&lt;br /&gt;
* There is a simple way to update whole Moodle via the web. Sue does not need to download the whole pack, unpack it locally and upload it via FTP to her server (in older versions this was very boring job that discouraged Sue from doing it). She is also happy that she does not need to compare the remote side with the ZIP contents to look for files that should be now removed (in older versions this was pretty challenging for her so she often found herself having some old files left at the server).&lt;br /&gt;
&lt;br /&gt;
=== Use case 4 ===&lt;br /&gt;
&lt;br /&gt;
* Bob, a friend of Sue, asks her for an assistance with a fresh Moodle installation. They are having a nice weekend in a beautiful village with very poor internet connectivity. Uploading the whole Moodle pack would take ages.&lt;br /&gt;
* Even in this case, there is no need to deal with the download, unzip and upload procedure - Sue just uploads a single small PHP file to the empty wwwroot of Bob&#039;s future server.&lt;br /&gt;
* Then she visits the script&#039;s URL and after providing some details into the form, the script fetches the whole Moodle package, unpacks it and redirects the browser to the /admin so that standard installation can continue.&lt;br /&gt;
&lt;br /&gt;
== Technical issues to deal with ==&lt;br /&gt;
&lt;br /&gt;
* In Use case 1 above, there is a new version of Moodle already uploaded to the server. We are in the middle of the upgrade process. It is generally very tricky to depend on any Moodle functionality in this moment. The code that actually fetches the packages from download.moodle.org must be independent of the Moodle itself. Otherwise, the complex chain of includes would lead to problems. In other words, we can&#039;t include config.php to fetch and deploy the ZIPs.&lt;br /&gt;
* For the same reasons, the part of the machinery that actually fetches the files from the download.moodle.org server in Use case 3, must be independent of the rest of Moodle. In other words, Moodle can&#039;t overwrite its own codes. Don&#039;t try it. Bad thing would happen with Gaia.&lt;br /&gt;
* In Use case 3, downloading full ~40MB ZIP is not ecological. There might be a way of having &amp;quot;incremental/patch packages&amp;quot; generated for each weekly build that would contain just a subset of files that were modified in that release.&lt;br /&gt;
* In Use case 3, we need to put the Moodle site into a hard maintenance mode prior to deploying the code so that there is no chance that a random user visits the site meantime.&lt;br /&gt;
* In Use case 4, we need some sort of authentication so that the actual deployment can&#039;t be executed by a random visitor (or a bot) that accesses the site before Sue does it. The script might generate a solid strong passphrase (token) into a text file in wwwroot. So that only people having access to the server via FTP can read the passphrase and copy it into the web form.&lt;br /&gt;
* Note that we always expect that Sue has its own way of doing full database and moodledata backups prior to any changes. Having an in-built tool to make such backup is out of scope of this project.&lt;br /&gt;
&lt;br /&gt;
== Implementation schedule ==&lt;br /&gt;
&lt;br /&gt;
* Episode IV: Use case 1 is implemented - installed plugins can be updated via the web only (MUST-HAVE for Moodle 2.4) - see [[:en:Automatic updates deployment]]&lt;br /&gt;
* Episode III: Use case 2 is implemented - new plugins can be installed (NICE-TO-HAVE for Moodle 2.4, MUST-HAVE for 2.5) - see [[On-click add-on installation]]&lt;br /&gt;
* Episode II: Use case 3 is implemented - Moodle core can be updated (NICE-TO-HAVE for 2.5, MUST-HAVE for 2.6)&lt;br /&gt;
* Episode I: Use case 4 is implemented - Moodle can be installed from scratch via a bootstrap file (NICE-TO-HAVE for 2.5 or 2.6)&lt;br /&gt;
&lt;br /&gt;
== Implementation plan ==&lt;br /&gt;
&lt;br /&gt;
=== Required components of the machinery ===&lt;br /&gt;
&lt;br /&gt;
* A standalone tool (script) that is able to fetch a ZIP package from a given URL, compare its MD5 content hash with a given value, unpack it, and deploy the content to a given location inside wwwroot.&lt;br /&gt;
* Modification of the &amp;quot;Plugins check&amp;quot; and &amp;quot;Plugins overview&amp;quot; admin pages so they provide a way to select available updates and pass required info to the standalone script mentioned above.&lt;br /&gt;
* Extending the REST API at the download.moodle.org so that it provides all required info (URL to download the ZIP from and the ZIP&#039;s MD5 hash).&lt;br /&gt;
* New admin tool that allows the administrator to browse the list of available plugins (compare to the community finder tool that lets you browse the list of available courses&lt;br /&gt;
&lt;br /&gt;
=== Overall logic flow ===&lt;br /&gt;
&lt;br /&gt;
[[image:automatic-update-deploy-1.png]]&lt;br /&gt;
&lt;br /&gt;
There are two places where a plugin update can be ignited from: 1) Plugins check page (in the middle of the upgrade process) and 2) Plugins overview page. We need to be able to ignite the deployment from both places while still re-use as much functionality as possible.&lt;br /&gt;
&lt;br /&gt;
1. Admin looks at say Plugins overview pgae&lt;br /&gt;
2. The page script (/admin/index.php) reads a singleton instance of available_update_deployer. It sets its own URL as the caller&#039;s URL (this one that actually accepts some params via HTTP) and the return URL.&lt;br /&gt;
3. When displaying the available update info, the singleton is used to generate a widget (single buttom currently) &amp;quot;Install this update&amp;quot;. Clicking the button lets the admin to review the request (what plugin, where from etc) and confrm the request.&lt;br /&gt;
4. When confirmed, the page redirects to a standalone script /mdeploy.php which actually makes the job.&lt;br /&gt;
5. The browser is then redirected back to the caller&#039;s return URL.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Available update notifications]] project (since Moodle 2.3).&lt;br /&gt;
* [[On-click add-on installation]] project (since Moodle 2.5).&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Automatic_Class_Loading_Proposal&amp;diff=64533</id>
		<title>Automatic Class Loading Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Automatic_Class_Loading_Proposal&amp;diff=64533"/>
		<updated>2025-02-10T07:43:06Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = [[Automatic class loading]]&lt;br /&gt;
|state = Integrated&lt;br /&gt;
|tracker = MDL-39854&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229474&lt;br /&gt;
|assignee = [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Automatic class loading is a feature that eliminates manual including of PHP files. It can be implemented only if you can derive the location of class from its name. Usually one class needs to be stored in one file.&lt;br /&gt;
&lt;br /&gt;
This is a proposal for standardisation of class naming and class file storage in Moodle using existing Frankenstyle rules.&lt;br /&gt;
&lt;br /&gt;
==Pros==&lt;br /&gt;
* improved coding style&lt;br /&gt;
* lower memory footprint&lt;br /&gt;
* enforcing of standardised class names and location of source files&lt;br /&gt;
* possibility to replace standard classes in local customisations via custom classloader without core modification&lt;br /&gt;
&lt;br /&gt;
==Cons==&lt;br /&gt;
* potentially lower performance because current Moodle class names are ambiguous and plugin locations are dynamic, workaround is to start using namespaces and rework plugin listing API&lt;br /&gt;
&lt;br /&gt;
==Namespaces==&lt;br /&gt;
&lt;br /&gt;
PHP 5.3.0 introduced a new concept called namespaces, this feature would significantly simplify the directory structure of classes directory.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* new \core\xxx_yyy() ---&amp;gt; in lib/classes/xxx_yyy.php&lt;br /&gt;
* new \core\xxx\yyy.php() ---&amp;gt; lib/classes/xxx/yyy.php&lt;br /&gt;
* new \core\event\base.php() ---&amp;gt; lib/classes/event/base.php&lt;br /&gt;
* new \core\event\something_happened() ---&amp;gt; lib/classes/event/something_happened.php&lt;br /&gt;
* new \mod_forum\event\post_rated() ---&amp;gt; mod/forum/classes/event/post_rated.php&lt;br /&gt;
&lt;br /&gt;
Pros:&lt;br /&gt;
* very fast&lt;br /&gt;
* easy to understand&lt;br /&gt;
* fewer backwards compatibility problems&lt;br /&gt;
&lt;br /&gt;
Cons:&lt;br /&gt;
* few core developers know it&lt;br /&gt;
&lt;br /&gt;
==Legacy plugin class naming==&lt;br /&gt;
&lt;br /&gt;
The general plugin class name should be:&lt;br /&gt;
plugintype_pluginname_typeofclass_someclass&lt;br /&gt;
&lt;br /&gt;
Unfortunately the pluginname part might contain multiple underscores which may lead to various problems.&lt;br /&gt;
&lt;br /&gt;
The algorithm for finding of the class file location from given class name is:&lt;br /&gt;
# we have a class &#039;&#039;aaa_bbb_ccc_ddd_eee_fff&#039;&#039;&lt;br /&gt;
# aaa is always the plugin type, it can not be word core or moodle, ex.: mod, tool, block&lt;br /&gt;
# bbb is a candidate for plugin name, if this plugin exists look for file &#039;&#039;bbbdir/classes/ccc_ddd_eee_fff.php&#039;&#039;&lt;br /&gt;
# if plugin or class does not exist bbb_ccc is another candidate for plugin name, look for &#039;&#039;bbb_cccdir/classes/ddd_eee_fff.php&#039;&#039;&lt;br /&gt;
# repeat until reaching the limit of underscores in plugin name (5?)&lt;br /&gt;
&lt;br /&gt;
==Legacy core class naming==&lt;br /&gt;
The general core class name should be:&lt;br /&gt;
core_optionalsubsystem_typeofclass_someclass&lt;br /&gt;
&lt;br /&gt;
The algorithm for finding of the class file location from given class name is:&lt;br /&gt;
# we have a class &#039;&#039;core_aaa_bbb_ccc&#039;&#039;&lt;br /&gt;
# look for file &#039;&#039;/lib/classes/aaa_bbb_ccc.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We could also hardcode exception for non-frankenstyle class names and custom file locations.&lt;br /&gt;
&lt;br /&gt;
==Potential candidates==&lt;br /&gt;
* new events classes&lt;br /&gt;
* admin settings in plugins&lt;br /&gt;
* any new core feature implemented using OOP&lt;br /&gt;
* internal implementation of add-ons&lt;br /&gt;
* some existing core subsytems&lt;br /&gt;
* some existing plugins that already use these rules (ex.: tinymce plugins)&lt;br /&gt;
&lt;br /&gt;
==Backwards compatibility==&lt;br /&gt;
There should not be any significant problems because the classes subdirectory is searched only if class not already included - classloader is used only for missing classes. Please note this proposal does not change Frankenstyle class naming rules for plugins in any way.&lt;br /&gt;
&lt;br /&gt;
We should probably require the use of automatic class loading only in new APIs and let add-on developers decide the rest for themselves. It is also technically possible to migrate some existing classes from lib.php files to /classes/ while keeping 100% backwards compatibility.&lt;br /&gt;
&lt;br /&gt;
==Implementation steps==&lt;br /&gt;
# Finalise rules for class names, class file names and locations.&lt;br /&gt;
# Implement basic loader using current (slow) plugin API.&lt;br /&gt;
# Improve performance and stability by rewriting get_plugin_types(), get_plugin_list() and friends.&lt;br /&gt;
# Frankenstyle plugin info API should be self contained without any dependencies.&lt;br /&gt;
&lt;br /&gt;
==Frequently asked questions==&lt;br /&gt;
&lt;br /&gt;
; Why not use existing class loading standard? : The proposal builds on top of PSR-0, but it must take into account our ambiguous plugin naming rules and dynamic plugin locations.&lt;br /&gt;
; Is it compatible with 3rd party libraries? : Most probably yes, Frankenstyle was supposed to resolve this. This biggest current problem are short names without the &amp;quot;core_&amp;quot; prefix, this proposal would finally require all new core things to start with &amp;quot;core_&amp;quot;. It is unlikely that other projects use frankenstyle in top most namespace.&lt;br /&gt;
; Is this compatible with other classloaders? : Yes. spl_autoload_register() supports multiple class loaders, Frankenstyle loader should be the last one because it will be most expensive.&lt;br /&gt;
; Is this compatible with code obfuscators? : No! Moodle already breaks with them and we will never support it. This is GPL, there is no reason to hide anything.&lt;br /&gt;
; Why only one class per file? : Because it makes things easier for everybody.&lt;br /&gt;
&lt;br /&gt;
==See also== &lt;br /&gt;
* http://php.net/manual/en/language.oop5.autoload.php&lt;br /&gt;
* http://www.php.net/manual/en/function.spl-autoload-register.php&lt;br /&gt;
* https://tracker.moodle.org/browse/MDLSITE-2261&lt;br /&gt;
* [[Events API]]&lt;br /&gt;
* [[Frankenstyle]]&lt;br /&gt;
* [[Automatic class loading]]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Audio/Video_Capture_repository_plugin&amp;diff=64532</id>
		<title>Audio/Video Capture repository plugin</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Audio/Video_Capture_repository_plugin&amp;diff=64532"/>
		<updated>2025-02-10T07:40:51Z</updated>

		<summary type="html">&lt;p&gt;Sarjona: This page will not be migrated to new devdocs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:WillNotMigrate}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Audio/Video Capture repository plugin&lt;br /&gt;
|state = Coding Period&lt;br /&gt;
|tracker = CONTRIB-3631&lt;br /&gt;
|discussion = [http://moodle.org/mod/forum/discuss.php?d=202632#p883953 Forum - Post]&lt;br /&gt;
|assignee = Ankit Gupta&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;GSOC&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt; &#039;12&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
Audio/Video Capture repository plugin is of great utility to both teachers and students. Teachers can directly submit assignments or record audio/video lectures for the students. This project is for the implementation of the Audio/Video Capture repository plug-in which enables users to directly capture and upload their audio/video files to the server.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
Moodle 2.3 required&lt;br /&gt;
&lt;br /&gt;
== Project Details ==&lt;br /&gt;
=== Description ===&lt;br /&gt;
The ’A/V recorder’ module will use the Repository API and its own small API for integration of sound and video recording components and web services with Moodle. The module would have a UI which would receive requests for recording media. The A/V Module calls the ‘record’ module. The recorded media is then converted to a proper format (using ImaACPCM or Speex codecs) to be saved to the Moodle servers. The file is then uploaded to the servers by either using the existing plugins or a new module is created to accomplish the task. The module then saves the file name/location in the database. During the above operations the module would inherently interact with the Moodle Interface for various data operations/inter-module interactions.&lt;br /&gt;
&lt;br /&gt;
=== Implementation ===&lt;br /&gt;
I would be extending the NanoGong Java Applet to record, playback and save the content to web-pages for Moodle 2.0. The NanoGong applet is quite well-suited for the project and currently supports audio recording. NanoGong provides an extended HTML editor which would be integrated with the current editor provided by the default Moodle installation everywhere. Below are some of the prospects of using the applet (as mentioned in the NanoGong documentation)&lt;br /&gt;
&lt;br /&gt;
The editor would be customizable from the back-end with varying permissions for students, teachers and administrators over the record, playback and speed controls. The functionality will be as follows : &lt;br /&gt;
&lt;br /&gt;
For students using Moodle :&lt;br /&gt;
Students can submit their voice/video messages using the extended html editor. These messages can be deleted and changed provided it is not locked by the corresponding teacher giving the assignment.&lt;br /&gt;
&lt;br /&gt;
For teachers using Moodle :&lt;br /&gt;
Teacher can view all the messages submitted and choose to lock/change or assign score to a  given assignment based on the message. Alternatively the applet can be used by teachers to record video/audio lectures. &lt;br /&gt;
&lt;br /&gt;
As for the Video part, no known open source alternatives exists currently for a video recording Java Applet. I have taken a good look at Vimas, the enterprise Applet for Video capturing and would look to build something on those lines. The video recording applet would allow recording videos in mp4 format (H.264 video and AAC audio) on the web page and upload it on the web server via HTTP. I would be using the Java Media Framework (JMF) to capture the audio and video stream.&lt;br /&gt;
&lt;br /&gt;
=== Schedule of Deliverables ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pre-phase&#039;&#039;&#039; (10th May - 21st May) :&lt;br /&gt;
Pre-phase would involve assembling all the pre-requisites for the coding period. Talking to the mentors and reading the documentation to be in good stead before the coding period begins.&lt;br /&gt;
Also maintaining a blog to track day to day progress and track reviews by mentors, would be done during this period.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;First-phase&#039;&#039;&#039; (21st May - 9th July)&lt;br /&gt;
Deliverables : &lt;br /&gt;
&lt;br /&gt;
21st May - 28th May&lt;br /&gt;
Code the entire framework for the plugin. Build a basic back bone wherein addition of these media capture modules can be easily done. &lt;br /&gt;
&lt;br /&gt;
29th May - 4th June&lt;br /&gt;
Port the NanoGong applet to Moodle 2.0 and integrate the functionality within the module.&lt;br /&gt;
&lt;br /&gt;
5th June - 19th June&lt;br /&gt;
Complete the Audio Plugin Front-end and back-end which manages permissions for audio recording for students, teachers, various options for playback, save and speed control. &lt;br /&gt;
&lt;br /&gt;
20th June - 9th July&lt;br /&gt;
Look for open-source alternatives for Vimas and start the development/integration of the Video plugin in to the Module.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Second-phase&#039;&#039;&#039; (11th July - 1st August)&lt;br /&gt;
Deliverables : &lt;br /&gt;
&lt;br /&gt;
11th July - 18th July&lt;br /&gt;
Entire back-end + front-end for the module should be complete.&lt;br /&gt;
&lt;br /&gt;
19th July - 25th July&lt;br /&gt;
Customize the Video plug-in and test the support for different frames and audio/video quality on various browsers.&lt;br /&gt;
&lt;br /&gt;
26th July - 1st August&lt;br /&gt;
Extra time for full implementation of the Video plug-in . This would involve intensive testing and bug-fixing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Post-phase&#039;&#039;&#039; (12th August - 20th August) :&lt;br /&gt;
This period is exclusively reserved for final testing, minor bug fixes or enhancements to the front-end, documentation of the entire code, review from the mentors and minor changes to the code.&lt;br /&gt;
&lt;br /&gt;
== Relevant Links ==&lt;br /&gt;
=== Ideas List ===&lt;br /&gt;
* [https://docs.moodle.org/dev/Projects_for_new_developers Moodle - Google Summer of Code 2012 Idea List]&lt;br /&gt;
=== Tracker ===&lt;br /&gt;
* [http://tracker.moodle.org/browse/CONTRIB-3631 An Audio/Video Capture repository plug-in]&lt;br /&gt;
=== GSoC Proposal ===&lt;br /&gt;
* [http://www.google-melange.com/gsoc/proposal/review/google/gsoc2012/ankitgupta_/1 Original Proposal - GSoC 2012]&lt;br /&gt;
=== Developer Blog ===&lt;br /&gt;
* [http://ankitgupta90.tumblr.com/ # Ankit Gupta]&lt;/div&gt;</summary>
		<author><name>Sarjona</name></author>
	</entry>
</feed>