Merge branch 'MDL-30271-switch-role-workshop' of git://github.com/mudrd8mz/moodle
authorSam Hemelryk <sam@moodle.com>
Wed, 30 Nov 2011 22:48:55 +0000 (11:48 +1300)
committerSam Hemelryk <sam@moodle.com>
Wed, 30 Nov 2011 22:48:55 +0000 (11:48 +1300)
84 files changed:
admin/settings/appearance.php
backup/cc/entity.resource.class.php
backup/cc/entity11.resource.class.php
backup/cc/schemas/domainProfile_1/common/dataTypes.xsd
backup/cc/schemas/domainProfile_1/dataTypes_localised.xsd
backup/cc/schemas/domainProfile_2/common/dataTypes.xsd
backup/cc/schemas/domainProfile_2/dataTypes_localised.xsd
backup/cc/schemas/domainProfile_4/ims_qtiasiv1p2_localised.xsd
backup/cc/schemas/domainProfile_4/xml.xsd
backup/cc/schemas/xml.xsd
backup/cc/schemas11/xml.xsd
backup/moodle2/restore_stepslib.php
blocks/community/renderer.php
calendar/preferences_form.php
course/externallib.php
enrol/self/edit_form.php
enrol/self/lang/en/enrol_self.php
filter/mediaplugin/simpletest/testfiltermediaplugin.php
grade/grading/simpletest/testlib.php
grade/report/grader/styles.css
install/lang/en/install.php
install/lang/fr/install.php
install/lang/hu/install.php
install/lang/ne/langconfig.php [new file with mode: 0644]
install/lang/sv_fi/langconfig.php [new file with mode: 0644]
install/lang/zh_cn/install.php
lang/en/error.php
lang/en/webservice.php
lib/db/services.php
lib/db/upgrade.php
lib/db/upgradelib.php
lib/filelib.php
lib/navigationlib.php
lib/outputcomponents.php
lib/upgrade.txt
mod/assignment/styles.css
mod/folder/lib.php
mod/forum/index.php
mod/forum/lib.php
mod/glossary/editcategories.php
mod/lti/OAuthBody.php
mod/lti/simpletest/testlocallib.php
mod/page/lib.php
mod/resource/lib.php
mod/scorm/report/interactions/report.php
mod/survey/report.php
mod/url/lib.php
mod/url/locallib.php
mod/wiki/edit_form.php
pluginfile.php
portfolio/boxnet/lib.php
question/format/xml/format.php
question/type/calculated/datasetitems_form.php
question/type/calculated/edit_calculated_form.php
question/type/calculated/questiontype.php
question/type/calculatedmulti/edit_calculatedmulti_form.php
question/type/calculatedsimple/edit_calculatedsimple_form.php
question/type/multianswer/edit_multianswer_form.php
repository/dropbox/lib.php
repository/dropbox/locallib.php
tag/locallib.php
theme/afterburner/config.php
theme/afterburner/lang/en/theme_afterburner.php
theme/afterburner/layout/default.php
theme/afterburner/lib.php [new file with mode: 0644]
theme/afterburner/pix/images/logo.jpg [new file with mode: 0644]
theme/afterburner/settings.php [new file with mode: 0644]
theme/afterburner/style/afterburner_styles.css
theme/anomaly/config.php
theme/anomaly/layout/general.php
theme/anomaly/layout/report.php
theme/anomaly/style/base.css
theme/anomaly/style/browser.css
theme/anomaly/style/dock.css [new file with mode: 0644]
theme/anomaly/style/general.css
theme/base/style/core.css
theme/standard/style/grade.css
user/profile.php
user/view.php
version.php
webservice/lib.php
webservice/pluginfile.php [new file with mode: 0644]
webservice/simpletest/testwebservice.php
webservice/upload.php

index 7da5786..ce02d9d 100644 (file)
@@ -56,8 +56,16 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
             6 => get_string('saturday', 'calendar')
         )));
     $temp->add(new admin_setting_special_calendar_weekend());
-    $temp->add(new admin_setting_configtext('calendar_lookahead',get_string('configlookahead','admin'),get_string('helpupcominglookahead', 'admin'),21,PARAM_INT));
-    $temp->add(new admin_setting_configtext('calendar_maxevents',get_string('configmaxevents','admin'),get_string('helpupcomingmaxevents', 'admin'),10,PARAM_INT));
+    $options = array();
+    for ($i=1; $i<=99; $i++) {
+        $options[$i] = $i;
+    }
+    $temp->add(new admin_setting_configselect('calendar_lookahead',get_string('configlookahead','admin'),get_string('helpupcominglookahead', 'admin'),21,$options));
+    $options = array();
+    for ($i=1; $i<=20; $i++) {
+        $options[$i] = $i;
+    }
+    $temp->add(new admin_setting_configselect('calendar_maxevents',get_string('configmaxevents','admin'),get_string('helpupcomingmaxevents', 'admin'),10,$options));
     $temp->add(new admin_setting_configcheckbox('enablecalendarexport', get_string('enablecalendarexport', 'admin'), get_string('configenablecalendarexport','admin'), 1));
     $temp->add(new admin_setting_configtext('calendar_exportsalt', get_string('calendarexportsalt','admin'), get_string('configcalendarexportsalt', 'admin'), random_string(60)));
     $ADMIN->add('appearance', $temp);
index b610011..b2f7b87 100644 (file)
@@ -43,6 +43,9 @@ class cc_resource extends entities {
     }
 
     private function create_node_course_modules_mod_resource ($sheet_mod_resource, $instance) {
+        global $CFG;
+
+        require_once($CFG->libdir.'/validateurlsyntax.php');
 
         $link = '';
         $mod_alltext = '';
@@ -77,9 +80,19 @@ class cc_resource extends entities {
 
                 if (!empty($resource)) {
                     $xpath = cc2moodle::newx_path($resource, cc2moodle::getresourcens());
-                    $resource = $xpath->query('/wl:webLink/wl:url/@href');
+                    $resource = $xpath->query('//url/@href');
                     if ($resource->length > 0) {
-                        $link = $resource->item(0)->nodeValue;
+                        $rawlink = $resource->item(0)->nodeValue;
+                        if (!validateUrlSyntax($rawlink, 's+')) {
+                            $changed = rawurldecode($rawlink);
+                            if (validateUrlSyntax($changed, 's+')) {
+                                $link = $changed;
+                            } else {
+                                $link = 'http://invalidurldetected/';
+                            }
+                        } else {
+                            $link = $rawlink;
+                        }
                     }
                 }
             }
@@ -98,7 +111,7 @@ class cc_resource extends entities {
         $mod_options   = 'objectframe';
         $mod_reference = $link;
         //detected if we are dealing with html file
-        if (!empty($link) && ($instance['common_cartriedge_type'] == cc112moodle::CC_TYPE_WEBCONTENT)) {
+        if (!empty($link) && ($instance['common_cartriedge_type'] == cc2moodle::CC_TYPE_WEBCONTENT)) {
             $ext = strtolower(pathinfo($link, PATHINFO_EXTENSION));
             if (in_array($ext, array('html', 'htm', 'xhtml'))) {
                 $mod_type = 'html';
index adadce0..bc5bb5a 100644 (file)
@@ -43,6 +43,9 @@ class cc11_resource extends entities11 {
     }
 
     private function create_node_course_modules_mod_resource ($sheet_mod_resource, $instance) {
+        global $CFG;
+
+        require_once($CFG->libdir.'/validateurlsyntax.php');
 
         $link = '';
         $mod_alltext = '';
@@ -87,7 +90,17 @@ class cc11_resource extends entities11 {
                     $xpath = cc112moodle::newx_path($resource, cc112moodle::$resourcens);
                     $resource = $xpath->query('/wl:webLink/wl:url/@href');
                     if ($resource->length > 0) {
-                        $link = $resource->item(0)->nodeValue;
+                        $rawlink = $resource->item(0)->nodeValue;
+                        if (!validateUrlSyntax($rawlink, 's+')) {
+                            $changed = rawurldecode($rawlink);
+                            if (validateUrlSyntax($changed, 's+')) {
+                                $link = $changed;
+                            } else {
+                                $link = 'http://invalidurldetected/';
+                            }
+                        } else {
+                            $link = $rawlink;
+                        }
                     }
                 }
             }
index 25921a4..4e0136b 100644 (file)
@@ -34,7 +34,7 @@
        <!-- LanguageId -->
        <xs:complexType name="LanguageId">
                <xs:simpleContent>
-                       <xs:extension base="xs:language">
+                       <xs:extension base="xs:token">
                                <xs:attributeGroup ref="ex:customAttributes"/>
                        </xs:extension>
                </xs:simpleContent>
@@ -66,7 +66,7 @@
        <xs:complexType name="LangString">
                <xs:simpleContent>
                        <xs:extension base="CharacterString">
-                               <xs:attribute name="language" type="xs:language"/>
+                               <xs:attribute name="language" type="xs:token"/>
                                <xs:attributeGroup ref="ex:customAttributes"/>
                        </xs:extension>
                </xs:simpleContent>
index 75ce21e..cfe6d48 100644 (file)
@@ -43,7 +43,7 @@
        <!-- LanguageId -->
        <xs:complexType name="LanguageId">
                <xs:simpleContent>
-                       <xs:extension base="xs:language">
+                       <xs:extension base="xs:token">
                                <xs:attributeGroup ref="ex:customAttributes" />
                        </xs:extension>
                </xs:simpleContent>
@@ -78,7 +78,7 @@
        <xs:complexType name="LangString">
                <xs:simpleContent>
                        <xs:extension base="CharacterString">
-                               <xs:attribute name="language" type="xs:language" />
+                               <xs:attribute name="language" type="xs:token" />
                                <xs:attributeGroup ref="ex:customAttributes" />
                        </xs:extension>
                </xs:simpleContent>
index 801ac7b..a92da0c 100644 (file)
@@ -34,7 +34,7 @@
        <!-- LanguageId -->
        <xs:complexType name="LanguageId">
                <xs:simpleContent>
-                       <xs:extension base="xs:language">
+                       <xs:extension base="xs:token">
                                <xs:attributeGroup ref="ex:customAttributes"/>
                        </xs:extension>
                </xs:simpleContent>
index c70734a..07fd062 100644 (file)
@@ -43,7 +43,7 @@
        <!-- LanguageId -->
        <xs:complexType name="LanguageId">
                <xs:simpleContent>
-                       <xs:extension base="xs:language">
+                       <xs:extension base="xs:token">
                                <xs:attributeGroup ref="ex:customAttributes" />
                        </xs:extension>
                </xs:simpleContent>
@@ -75,7 +75,7 @@
        <xs:complexType name="LangString">
                <xs:simpleContent>
                        <xs:extension base="CharacterString">
-                               <xs:attribute name="language" type="xs:language" />
+                               <xs:attribute name="language" type="xs:token" />
                                <xs:attributeGroup ref="ex:customAttributes" />
                        </xs:extension>
                </xs:simpleContent>
index 671d84e..202e817 100644 (file)
                                <xs:element ref="mat_extension" minOccurs="0" maxOccurs="0" />
                        </xs:choice>
                </xs:sequence>
-               <xs:attribute name="attribute3" type="xs:language" />
+               <xs:attribute name="attribute3" type="xs:token" />
        </xs:complexType>
        <!-- ********* -->
        <!-- ** and ** -->
                                <xs:attribute name="charset" type="xs:string" default="ascii-us" />
                                <xs:attribute name="uri" type="xs:string" />
                                <xs:attribute ref="xml:space" default="default" />
-                               <xs:attribute name="attribute11" type="xs:language" />
+                               <xs:attribute name="attribute11" type="xs:token" />
                                <xs:attribute name="entityref" type="xs:ENTITY" use="prohibited" />
                                <xs:attribute name="width" type="xs:string" />
                                <xs:attribute name="height" type="xs:string" />
                        <xs:element name="altmaterial" type="altmaterialType" minOccurs="0" maxOccurs="unbounded" />
                </xs:sequence>
                <xs:attribute name="label" type="string256" />
-               <xs:attribute name="attribute5" type="xs:language" />
+               <xs:attribute name="attribute5" type="xs:token" />
        </xs:complexType>
        <!-- ****************** -->
        <!-- ** material_ref ** -->
                                <xs:attribute name="charset" type="xs:string" default="ascii-us" />
                                <xs:attribute name="uri" type="xs:string" />
                                <xs:attribute ref="xml:space" default="default" />
-                               <xs:attribute name="attribute11" type="xs:language" />
+                               <xs:attribute name="attribute11" type="xs:token" />
                                <xs:attribute name="entityref" type="xs:ENTITY" use="prohibited" />
                                <xs:attribute name="width" type="xs:string" />
                                <xs:attribute name="height" type="xs:string" />
                        </xs:choice>
                </xs:sequence>
                <xs:attribute name="label" type="xs:string" />
-               <xs:attribute name="attribute5" type="xs:language" />
+               <xs:attribute name="attribute5" type="xs:token" />
                <xs:attribute name="y0" type="xs:string" />
                <xs:attribute name="x0" type="xs:string" />
                <xs:attribute name="width" type="xs:string" />
                </xs:sequence>
                <xs:attribute name="ident" type="xs:string" use="required" />
                <xs:attribute name="title" type="xs:string" />
-               <xs:attribute name="attribute7" type="xs:language" />
+               <xs:attribute name="attribute7" type="xs:token" />
        </xs:complexType>
        <!-- ******************** -->
        <!-- ** sectioncontrol ** -->
index 8e0c9d4..b96eef5 100644 (file)
          the empty string.</xs:documentation>
   </xs:annotation>
   <xs:simpleType>
-   <xs:union memberTypes="xs:language">
+   <xs:union memberTypes="xs:token">
     <xs:simpleType>    
      <xs:restriction base="xs:string">
       <xs:enumeration value="" />
index d8d39e7..ff94e18 100644 (file)
@@ -75,7 +75,7 @@
    </xs:documentation>
   </xs:annotation>
   <xs:simpleType>
-   <xs:union memberTypes="xs:language">
+   <xs:union memberTypes="xs:token">
     <xs:simpleType>    
      <xs:restriction base="xs:string">
       <xs:enumeration value=""/>
index 8e0c9d4..b96eef5 100644 (file)
          the empty string.</xs:documentation>
   </xs:annotation>
   <xs:simpleType>
-   <xs:union memberTypes="xs:language">
+   <xs:union memberTypes="xs:token">
     <xs:simpleType>    
      <xs:restriction base="xs:string">
       <xs:enumeration value="" />
index ae93170..f83b7c3 100644 (file)
@@ -2425,8 +2425,6 @@ class restore_module_structure_step extends restore_structure_step {
  *  - Activity includes completion info (file_exists)
  */
 class restore_userscompletion_structure_step extends restore_structure_step {
-    private $done = array();
-
     /**
      * To conditionally decide if this step must be executed
      * Note the "settings" conditions are evaluated in the
@@ -2470,15 +2468,14 @@ class restore_userscompletion_structure_step extends restore_structure_step {
         $data->userid = $this->get_mappingid('user', $data->userid);
         $data->timemodified = $this->apply_date_offset($data->timemodified);
 
+        // Find the existing record
+        $existing = $DB->get_record('course_modules_completion', array(
+                'coursemoduleid' => $data->coursemoduleid,
+                'userid' => $data->userid), 'id, timemodified');
         // Check we didn't already insert one for this cmid and userid
         // (there aren't supposed to be duplicates in that field, but
         // it was possible until MDL-28021 was fixed).
-        $key = $data->coursemoduleid . ',' . $data->userid;
-        if (array_key_exists($key, $this->done)) {
-            // Find the existing record
-            $existing = $DB->get_record('course_modules_completion', array(
-                    'coursemoduleid' => $data->coursemoduleid,
-                    'userid' => $data->userid), 'id, timemodified');
+        if ($existing) {
             // Update it to these new values, but only if the time is newer
             if ($existing->timemodified < $data->timemodified) {
                 $data->id = $existing->id;
@@ -2487,17 +2484,8 @@ class restore_userscompletion_structure_step extends restore_structure_step {
         } else {
             // Normal entry where it doesn't exist already
             $DB->insert_record('course_modules_completion', $data);
-            // Remember this entry
-            $this->done[$key] = true;
         }
     }
-
-    protected function after_execute() {
-        // This gets called once per activity (according to my testing).
-        // Clearing the array isn't strictly required, but avoids using
-        // unnecessary memory.
-        $this->done = array();
-    }
 }
 
 /**
index 5eb9d85..1df8f82 100644 (file)
@@ -193,6 +193,8 @@ class block_community_renderer extends plugin_renderer_base {
 
 
                 //Create course content html
+                $blocks = get_plugin_list('block');
+                $activities = get_plugin_list('mod');
                 if (!empty($course->contents)) {
                     $activitieshtml = '';
                     $blockhtml = '';
@@ -202,14 +204,22 @@ class block_community_renderer extends plugin_renderer_base {
                             if (!empty($blockhtml)) {
                                 $blockhtml .= ' - ';
                             }
-                            $blockhtml .= get_string('pluginname', 'block_' . $content->modulename)
-                                    . " (" . $content->contentcount . ")";
+                            if (array_key_exists($content->modulename, $blocks)) {
+                                $blockname = get_string('pluginname', 'block_' . $content->modulename);
+                            } else {
+                                $blockname = $content->modulename;
+                            }
+                            $blockhtml .= $blockname . " (" . $content->contentcount . ")";
                         } else {
                             if (!empty($activitieshtml)) {
                                 $activitieshtml .= ' - ';
                             }
-                            $activitieshtml .= get_string('modulename', $content->modulename)
-                                    . " (" . $content->contentcount . ")";
+                            if (array_key_exists($content->modulename, $activities)) {
+                                $activityname = get_string('modulename', $content->modulename);
+                            } else {
+                                $activityname = $content->modulename;
+                            }
+                            $activitieshtml .= $activityname . " (" . $content->contentcount . ")";
                         }
                     }
 
index 828055d..0ad0fb2 100644 (file)
@@ -71,7 +71,7 @@ class calendar_preferences_form extends moodleform {
         $mform->addHelpButton('maxevents', 'pref_maxevents', 'calendar');
 
         $options = array();
-        for ($i=1; $i<=20; $i++) {
+        for ($i=1; $i<=99; $i++) {
             $options[$i] = $i;
         }
         $mform->addElement('select', 'lookahead', get_string('pref_lookahead', 'calendar'), $options);
index 3724e30..e6a86ea 100644 (file)
@@ -33,6 +33,209 @@ require_once("$CFG->libdir/externallib.php");
  */
 class core_course_external extends external_api {
 
+    /**
+     * Returns description of method parameters
+     * @return external_function_parameters
+     */
+    public static function get_course_contents_parameters() {
+        return new external_function_parameters(
+                array('courseid' => new external_value(PARAM_INT, 'course id'),
+                      'options' => new external_multiple_structure (
+                              new external_single_structure(
+                                    array('name' => new external_value(PARAM_ALPHANUM, 'option name'),
+                                          'value' => new external_value(PARAM_RAW, 'the value of the option, this param is personaly validated in the external function.')
+                              )
+                      ), 'Options, not used yet, might be used in later version', VALUE_DEFAULT, array())
+                )
+        );
+    }
+
+    /**
+     * Get course contents
+     * @param int $courseid
+     * @param array $options, not used yet, might be used in later version
+     * @return array
+     */
+    public static function get_course_contents($courseid, $options) {
+        global $CFG, $DB;
+        require_once($CFG->dirroot . "/course/lib.php");
+
+        //validate parameter
+        $params = self::validate_parameters(self::get_course_contents_parameters(),
+                        array('courseid' => $courseid, 'options' => $options));
+
+        //retrieve the course
+        $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
+
+        //check course format exist
+        if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
+            throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null, get_string('courseformatnotfound', 'error', '', $course->format));
+        } else {
+            require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
+        }
+
+        // now security checks
+        $context = get_context_instance(CONTEXT_COURSE, $course->id);
+        try {
+            self::validate_context($context);
+        } catch (Exception $e) {
+            $exceptionparam = new stdClass();
+            $exceptionparam->message = $e->getMessage();
+            $exceptionparam->courseid = $course->id;
+            throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
+        }
+
+        $canupdatecourse = has_capability('moodle/course:update', $context);
+
+        //create return value
+        $coursecontents = array();
+
+        if ($canupdatecourse or $course->visible
+                or has_capability('moodle/course:viewhiddencourses', $context)) {
+
+            //retrieve sections
+            $modinfo = get_fast_modinfo($course);
+            $sections = get_all_sections($course->id);
+
+            //for each sections (first displayed to last displayed)
+            foreach ($sections as $key => $section) {
+
+                $showsection = (has_capability('moodle/course:viewhiddensections', $context) or $section->visible or !$course->hiddensections);
+                if (!$showsection) {
+                    continue;
+                }
+
+                // reset $sectioncontents
+                $sectionvalues = array();
+                $sectionvalues['id'] = $section->id;
+                $sectionvalues['name'] = get_section_name($course, $section);
+                $summary = file_rewrite_pluginfile_urls($section->summary, 'webservice/pluginfile.php', $context->id, 'course', 'section', $section->id);
+                $sectionvalues['visible'] = $section->visible;
+                $sectionvalues['summary'] = format_text($summary, $section->summaryformat);
+                $sectioncontents = array();
+
+                //for each module of the section
+                foreach ($modinfo->sections[$section->section] as $cmid) { //matching /course/lib.php:print_section() logic
+                    $cm = $modinfo->cms[$cmid];
+
+                    // stop here if the module is not visible to the user
+                    if (!$cm->uservisible) {
+                        continue;
+                    }
+
+                    $module = array();
+
+                    //common info (for people being able to see the module or availability dates)
+                    $module['id'] = $cm->id;
+                    $module['name'] = format_string($cm->name, true);
+                    $module['modname'] = $cm->modname;
+                    $module['modplural'] = $cm->modplural;
+                    $module['modicon'] = $cm->get_icon_url()->out(false);
+                    $module['indent'] = $cm->indent;
+
+                    $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+
+                    if (!empty($cm->showdescription)) {
+                        $module['description'] = $cm->get_content();
+                    }
+
+                    //url of the module
+                    $url = $cm->get_url();
+                    if ($url) { //labels don't have url
+                        $module['url'] = $cm->get_url()->out();
+                    }
+
+                    $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
+                                        get_context_instance(CONTEXT_MODULE, $cm->id));
+                    //user that can view hidden module should know about the visibility
+                    $module['visible'] = $cm->visible;
+
+                    //availability date (also send to user who can see hidden module when the showavailabilyt is ON)
+                    if ($canupdatecourse or ($CFG->enableavailability && $canviewhidden && $cm->showavailability)) {
+                        $module['availablefrom'] = $cm->availablefrom;
+                        $module['availableuntil'] = $cm->availableuntil;
+                    }
+
+                    $baseurl = 'webservice/pluginfile.php';
+
+                    //call $modulename_export_contents
+                    //(each module callback take care about checking the capabilities)
+                    require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
+                    $getcontentfunction = $cm->modname.'_export_contents';
+                    if (function_exists($getcontentfunction)) {
+                        if ($contents = $getcontentfunction($cm, $baseurl)) {
+                            $module['contents'] = $contents;
+                        }
+                    }
+
+                    //assign result to $sectioncontents
+                    $sectioncontents[] = $module;
+
+                }
+                $sectionvalues['modules'] = $sectioncontents;
+
+                // assign result to $coursecontents
+                $coursecontents[] = $sectionvalues;
+            }
+        }
+        return $coursecontents;
+    }
+
+    /**
+     * Returns description of method result value
+     * @return external_description
+     */
+    public static function get_course_contents_returns() {
+        return new external_multiple_structure(
+            new external_single_structure(
+                array(
+                    'id' => new external_value(PARAM_INT, 'Section ID'),
+                    'name' => new external_value(PARAM_TEXT, 'Section name'),
+                    'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
+                    'summary' => new external_value(PARAM_RAW, 'Section description'),
+                    'modules' => new external_multiple_structure(
+                            new external_single_structure(
+                                array(
+                                    'id' => new external_value(PARAM_INT, 'activity id'),
+                                    'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
+                                    'name' => new external_value(PARAM_TEXT, 'activity module name'),
+                                    'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
+                                    'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
+                                    'modicon' => new external_value(PARAM_URL, 'activity icon url'),
+                                    'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
+                                    'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
+                                    'availablefrom' => new external_value(PARAM_INT, 'module availability start date', VALUE_OPTIONAL),
+                                    'availableuntil' => new external_value(PARAM_INT, 'module availability en date', VALUE_OPTIONAL),
+                                    'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
+                                    'contents' => new external_multiple_structure(
+                                          new external_single_structure(
+                                              array(
+                                                  // content info
+                                                  'type'=> new external_value(PARAM_TEXT, 'a file or a folder or external link'),
+                                                  'filename'=> new external_value(PARAM_FILE, 'filename'),
+                                                  'filepath'=> new external_value(PARAM_PATH, 'filepath'),
+                                                  'filesize'=> new external_value(PARAM_INT, 'filesize'),
+                                                  'fileurl' => new external_value(PARAM_URL, 'downloadable file url', VALUE_OPTIONAL),
+                                                  'content' => new external_value(PARAM_RAW, 'Raw content, will be used when type is content', VALUE_OPTIONAL),
+                                                  'timecreated' => new external_value(PARAM_INT, 'Time created'),
+                                                  'timemodified' => new external_value(PARAM_INT, 'Time modified'),
+                                                  'sortorder' => new external_value(PARAM_INT, 'Content sort order'),
+
+                                                  // copyright related info
+                                                  'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
+                                                  'author' => new external_value(PARAM_TEXT, 'Content owner'),
+                                                  'license' => new external_value(PARAM_TEXT, 'Content license'),
+                                              )
+                                          ), VALUE_DEFAULT, array()
+                                      )
+                                )
+                            ), 'list of module'
+                    )
+                )
+            )
+        );
+    }
+
     /**
      * Returns description of method parameters
      * @return external_function_parameters
@@ -430,4 +633,4 @@ class moodle_course_external extends external_api {
         return core_course_external::create_courses_returns();
     }
 
-}
\ No newline at end of file
+}
index 338ccb6..5919d69 100644 (file)
@@ -59,9 +59,9 @@ class enrol_self_edit_form extends moodleform {
         $mform->setDefault('customint1', $plugin->get_config('groupkey'));
 
         if ($instance->id) {
-            $roles = get_default_enrol_roles($context, $instance->roleid);
+            $roles = $this->extend_assignable_roles($context, $instance->roleid);
         } else {
-            $roles = get_default_enrol_roles($context, $plugin->get_config('roleid'));
+            $roles = $this->extend_assignable_roles($context, $plugin->get_config('roleid'));
         }
         $mform->addElement('select', 'roleid', get_string('role', 'enrol_self'), $roles);
         $mform->setDefault('roleid', $plugin->get_config('roleid'));
@@ -156,4 +156,24 @@ class enrol_self_edit_form extends moodleform {
 
         return $errors;
     }
+
+    /**
+    * Gets a list of roles that this user can assign for the course as the default for self-enrolment
+    *
+    * @param context $context the context.
+    * @param integer $defaultrole the id of the role that is set as the default for self-enrolement
+    * @return array index is the role id, value is the role name
+    */
+    function extend_assignable_roles($context, $defaultrole) {
+        global $DB;
+        $roles = get_assignable_roles($context);
+        $sql = "SELECT r.id, r.name
+                  FROM {role} r
+                 WHERE r.id = $defaultrole";
+        $results = $DB->get_record_sql($sql);
+        if (isset($results->name)) {
+            $roles[$results->id] = $results->name;
+        }
+        return $roles;
+    }
 }
\ No newline at end of file
index a1edd91..af2c54c 100644 (file)
@@ -61,7 +61,7 @@ $string['pluginname'] = 'Self enrolment';
 $string['pluginname_desc'] = 'The self enrolment plugin allows users to choose which courses they want to participate in. The courses may be protected by an enrolment key. Internally the enrolment is done via the manual enrolment plugin which has to be enabled in the same course.';
 $string['requirepassword'] = 'Require enrolment key';
 $string['requirepassword_desc'] = 'Require enrolment key in new courses and prevent removing of enrolment key from existing courses.';
-$string['role'] = 'Assign role';
+$string['role'] = 'Default assigned role';
 $string['self:config'] = 'Configure self enrol instances';
 $string['self:manage'] = 'Manage enrolled users';
 $string['self:unenrol'] = 'Unenrol users from course';
index 139499d..e74bb2a 100644 (file)
@@ -92,7 +92,6 @@ class filter_mediaplugin_test extends UnitTestCase {
                             '<a >test test</a>',
                             '<ahref="http://moodle.org/testfile/test.mp3">sample</a>',
                             '<a href="" test></a>',
-                            '<a class="_blanktarget" href="http://moodle.org/testfile/test.flv?d=100x">test flv</a>',
                             '<a href="http://www.moodle.com/path/to?#param=29">test</a>',
                             '<a href="http://moodle.org/testfile/test.mp3">test mp3',
                             '<a href="http://moodle.org/testfile/test.mp3"test</a>',
index 5c61118..3e489b8 100644 (file)
@@ -131,11 +131,13 @@ class grading_manager_test extends UnitTestCase {
 
     public function test_tokenize() {
 
+        $UTFfailuremessage = 'A test using UTF-8 characters has failed. Consider updating PHP and PHP\'s PCRE or INTL extensions (MDL-30494)';
+
         $needle = "    šašek, \n\n   \r    a král;  \t";
         $tokens = testable_grading_manager::tokenize($needle);
-        $this->assertEqual(2, count($tokens));
-        $this->assertTrue(in_array('šašek', $tokens));
-        $this->assertTrue(in_array('král', $tokens));
+        $this->assertEqual(2, count($tokens), $UTFfailuremessage);
+        $this->assertTrue(in_array('šašek', $tokens), $UTFfailuremessage);
+        $this->assertTrue(in_array('král', $tokens), $UTFfailuremessage);
 
         $needle = ' "   šašek a král "    ';
         $tokens = testable_grading_manager::tokenize($needle);
@@ -153,8 +155,18 @@ class grading_manager_test extends UnitTestCase {
 
         $needle = '<span>Aha</span>, then who\'s a bad guy here he?';
         $tokens = testable_grading_manager::tokenize($needle);
-        $this->assertTrue(in_array('span', $tokens));
+        $this->assertEqual(8, count($tokens));
+        $this->assertTrue(in_array('span', $tokens)); // Extracted the tag name
         $this->assertTrue(in_array('Aha', $tokens));
-        $this->assertTrue(in_array('who', $tokens));
+        $this->assertTrue(in_array('who', $tokens)); // Removed the trailing 's
+        $this->assertTrue(!in_array('a', $tokens)); //Single letter token was dropped
+        $this->assertTrue(in_array('he', $tokens)); // Removed the trailing ?
+
+        $needle = 'grammar, "english language"';
+        $tokens = testable_grading_manager::tokenize($needle);
+        $this->assertTrue(in_array('grammar', $tokens));
+        $this->assertTrue(in_array('english', $tokens));
+        $this->assertTrue(in_array('language', $tokens));
+        $this->assertTrue(!in_array('english language', $tokens)); // Quoting part of the string is not supported
     }
 }
index 7d9c44c..b5a3f95 100644 (file)
@@ -539,6 +539,14 @@ table#user-grades td.ajax {
 text-align:left;
 }
 
+.dir-rtl table#user-grades td.userfield,
+.dir-rtl table#user-grades th,
+.path-grade-report-grader.dir-rtl  div.gradeparent,
+.path-grade-report-grader.dir-rtl  .ie6 form,
+.dir-rtl table#user-grades td.ajax {
+text-align:right;
+}
+
 .path-grade-report-grader .gradeparent {
     overflow:auto;
 }
index cb1bc0b..652120c 100644 (file)
@@ -41,6 +41,7 @@ $string['databasehost'] = 'Database host';
 $string['databasename'] = 'Database name';
 $string['databasetypehead'] = 'Choose database driver';
 $string['dataroot'] = 'Data directory';
+$string['datarootpermission'] = 'Data directories permission';
 $string['dbprefix'] = 'Tables prefix';
 $string['dirroot'] = 'Moodle directory';
 $string['environmenthead'] = 'Checking your environment ...';
index 81c9ae9..10da099 100644 (file)
@@ -41,6 +41,7 @@ $string['databasehost'] = 'Serveur de base de données';
 $string['databasename'] = 'Nom de la base de données';
 $string['databasetypehead'] = 'Sélectionner un pilote de base de données';
 $string['dataroot'] = 'Dossier de données';
+$string['datarootpermission'] = 'Permissions du dossier de données';
 $string['dbprefix'] = 'Préfixe des tables';
 $string['dirroot'] = 'Dossier Moodle';
 $string['environmenthead'] = 'Vérification de l\'environnement...';
index c2b48e3..85b4ce0 100644 (file)
@@ -41,6 +41,7 @@ $string['databasehost'] = 'Az adatbázis gazdagépe';
 $string['databasename'] = 'Az adatbázis neve';
 $string['databasetypehead'] = 'Adatbázismotor kiválasztása';
 $string['dataroot'] = 'Adatkönyvtár';
+$string['datarootpermission'] = 'Engedély adatkönyvtárakhoz';
 $string['dbprefix'] = 'Táblázat előtagja';
 $string['dirroot'] = 'Moodle-könyvtár';
 $string['environmenthead'] = 'Környezetének ellenőrzése ...';
diff --git a/install/lang/ne/langconfig.php b/install/lang/ne/langconfig.php
new file mode 100644 (file)
index 0000000..b8d3c4f
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle 2.2beta installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'नेपाली';
diff --git a/install/lang/sv_fi/langconfig.php b/install/lang/sv_fi/langconfig.php
new file mode 100644 (file)
index 0000000..7e897d5
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle 2.2beta installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'sv';
+$string['thislanguage'] = 'Finlandssvenska';
index 11a0895..37e8b7e 100644 (file)
@@ -34,7 +34,7 @@ $string['admindirname'] = '管理目录';
 $string['availablelangs'] = '可用的语言包';
 $string['chooselanguagehead'] = '选择一种语言';
 $string['chooselanguagesub'] = '请选择在安装过程中使用的语言。这个语言也会成为网站的缺省语言,不过以后可以随时更改。';
-$string['clialreadyinstalled'] = '文件config.php已存在。如果您想升级网站,请使用admin/cli/upgrade.php';
+$string['clialreadyinstalled'] = '文件config.php已存在。如果您想升级此网站,请使用admin/cli/upgrade.php。';
 $string['cliinstallheader'] = 'Moodle {$a}命令行安装程序';
 $string['databasehost'] = '数据库主机';
 $string['databasename'] = '数据库名';
index f0e125a..3591183 100644 (file)
@@ -164,6 +164,7 @@ $string['couldnotassignrole'] = 'A serious but unspecified error occurred while
 $string['couldnotupdatenoexistinguser'] = 'Cannot update the user - user doesn\'t exist';
 $string['countriesphpempty'] = 'Error: The file countries.php in language pack {$a} is empty or missing.';
 $string['coursedoesnotbelongtocategory'] = 'The course doesn\'t belong to this category';
+$string['courseformatnotfound'] = 'The course format \'{$a}\' doesn\'t exist or is not recognized';
 $string['coursegroupunknown'] = 'Course corresponding to group {$a} not specified';
 $string['courseidnotfound'] = 'Course id doesn\'t exist';
 $string['coursemisconf'] = 'Course is misconfigured';
index 2d28d61..ea16baa 100644 (file)
@@ -43,6 +43,7 @@ $string['apiexplorernotavalaible'] = 'API explorer not available yet.';
 $string['arguments'] = 'Arguments';
 $string['authmethod'] = 'Authentication method';
 $string['cannotcreatetoken'] = 'No permission to create web service token for the service {$a}.';
+$string['cannotgetcoursecontents'] = 'Cannot get course contents';
 $string['configwebserviceplugins'] = 'For security reasons, only protocols that are in use should be enabled.';
 $string['context'] = 'Context';
 $string['createservicedescription'] = 'A service is a set of web service functions. You will allow the user to access to a new service. On the <strong>Add service</strong> page check \'Enable\' and \'Authorised users\' options. Select \'No required capability\'.';
@@ -74,6 +75,7 @@ $string['enableprotocols'] = 'Enable protocols';
 $string['enableprotocolsdescription'] = 'At least one protocol should be enabled. For security reasons, only protocols that are to be used should be enabled.';
 $string['enablews'] = 'Enable web services';
 $string['enablewsdescription'] = 'Web services must be enabled in Advanced features.';
+$string['enabledirectdownload'] = 'Web service file downloading must be enabled in external service settings';
 $string['entertoken'] = 'Enter a security key/token:';
 $string['error'] = 'Error: {$a}';
 $string['errorcatcontextnotvalid'] = 'You cannot execute functions in the category context (category id:{$a->catid}). The context error message was: {$a->message}';
@@ -160,6 +162,7 @@ $string['selectspecificuserdescription'] = 'Add the web services user as an auth
 $string['service'] = 'Service';
 $string['servicehelpexplanation'] = 'A service is a set of functions. A service can be accessed by all users or just specified users.';
 $string['servicename'] = 'Service name';
+$string['servicenotavailable'] = 'the web service is not available (it does not exist or it is disabled)';
 $string['servicesbuiltin'] = 'Built-in services';
 $string['servicescustom'] = 'Custom services';
 $string['serviceusers'] = 'Authorised users';
@@ -177,6 +180,7 @@ $string['token'] = 'Token';
 $string['tokenauthlog'] = 'Token authentication';
 $string['tokencreatedbyadmin'] = 'Can only be reset by administrator (*)';
 $string['tokencreator'] = 'Creator';
+$string['unknownoptionkey'] = 'Unknown option key ({$a})';
 $string['updateusersettings'] = 'Update';
 $string['userasclients'] = 'Users as clients with token';
 $string['userasclientsdescription'] = 'The following steps help you to set up the Moodle web service for users as clients. These steps also help to set up the recommended token (security keys) authentication method. In this use case, the user will generate his token from the security keys page via My profile settings.';
index f91ec49..e721810 100644 (file)
@@ -404,6 +404,15 @@ $functions = array(
         'capabilities'=> 'moodle/course:create,moodle/course:visibility',
     ),
 
+    'core_course_get_contents' => array(
+        'classname'   => 'core_course_external',
+        'methodname'  => 'get_course_contents',
+        'classpath'   => 'course/externallib.php',
+        'description' => 'Get course contents',
+        'type'        => 'read',
+        'capabilities'=> 'moodle/course:update,moodle/course:viewhiddencourses',
+    ),
+
     // === message related functions ===
 
     'moodle_message_send_instantmessages' => array(
@@ -474,7 +483,8 @@ $services = array(
             'moodle_notes_create_notes',
             'moodle_user_get_course_participants_by_id',
             'moodle_user_get_users_by_courseid',
-            'moodle_message_send_instantmessages'),
+            'moodle_message_send_instantmessages',
+            'core_course_get_contents'),
         'enabled' => 0,
         'restrictedusers' => 0,
         'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE,
index f209c40..6b6573c 100644 (file)
@@ -6819,7 +6819,8 @@ FROM
         if ($dbman->table_exists($table)) {
             $instances = $DB->get_records('block_instances', array('blockname'=>'search'));
             foreach($instances as $instance) {
-                context_helper::delete_instance(CONTEXT_BLOCK, $instance->id);
+                $context = context_block::instance($instance->id);
+                upgrade_cleanup_unwanted_block_contexts(array($context->id)); // do not use standard block deleting MDL-30517, there is no extra stuff used in block, so this should be safe
                 $DB->delete_records('block_positions', array('blockinstanceid' => $instance->id));
                 $DB->delete_records('block_instances', array('id' => $instance->id));
             }
index 84ce362..6f1455f 100644 (file)
@@ -192,7 +192,10 @@ function upgrade_migrate_user_icons() {
         upgrade_set_timeout(60); /// Give upgrade at least 60 more seconds
         $pbar->update($i, $count, "Migrated user icons $i/$count.");
 
-        $context = get_context_instance(CONTEXT_USER, $user->id);
+        if (!$context = get_context_instance(CONTEXT_USER, $user->id)) {
+            // deleted user
+            continue;
+        }
 
         if ($fs->file_exists($context->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
             // already converted!
index 02c3501..af72cf7 100644 (file)
@@ -3137,3 +3137,769 @@ class filetype_parser {
         return $this->result;
     }
 }
+
+/**
+ * This function delegates file serving to individual plugins
+ *
+ * @param string $relativepath
+ * @param bool $forcedownload
+ *
+ * @package    core
+ * @subpackage file
+ * @copyright  2008 Petr Skoda (http://skodak.org)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+function file_pluginfile($relativepath, $forcedownload) {
+    global $DB, $CFG, $USER;
+    // relative path must start with '/'
+    if (!$relativepath) {
+        print_error('invalidargorconf');
+    } else if ($relativepath[0] != '/') {
+        print_error('pathdoesnotstartslash');
+    }
+
+    // extract relative path components
+    $args = explode('/', ltrim($relativepath, '/'));
+
+    if (count($args) < 3) { // always at least context, component and filearea
+        print_error('invalidarguments');
+    }
+
+    $contextid = (int)array_shift($args);
+    $component = clean_param(array_shift($args), PARAM_COMPONENT);
+    $filearea  = clean_param(array_shift($args), PARAM_AREA);
+
+    list($context, $course, $cm) = get_context_info_array($contextid);
+
+    $fs = get_file_storage();
+
+    // ========================================================================================================================
+    if ($component === 'blog') {
+        // Blog file serving
+        if ($context->contextlevel != CONTEXT_SYSTEM) {
+            send_file_not_found();
+        }
+        if ($filearea !== 'attachment' and $filearea !== 'post') {
+            send_file_not_found();
+        }
+
+        if (empty($CFG->bloglevel)) {
+            print_error('siteblogdisable', 'blog');
+        }
+
+        if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) {
+            require_login();
+            if (isguestuser()) {
+                print_error('noguest');
+            }
+            if ($CFG->bloglevel == BLOG_USER_LEVEL) {
+                if ($USER->id != $entry->userid) {
+                    send_file_not_found();
+                }
+            }
+        }
+        $entryid = (int)array_shift($args);
+        if (!$entry = $DB->get_record('post', array('module'=>'blog', 'id'=>$entryid))) {
+            send_file_not_found();
+        }
+
+        if ('publishstate' === 'public') {
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+        } else if ('publishstate' === 'site') {
+            require_login();
+            //ok
+        } else if ('publishstate' === 'draft') {
+            require_login();
+            if ($USER->id != $entry->userid) {
+                send_file_not_found();
+            }
+        }
+
+        $filename = array_pop($args);
+        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+
+        if (!$file = $fs->get_file($context->id, $component, $filearea, $entryid, $filepath, $filename) or $file->is_directory()) {
+            send_file_not_found();
+        }
+
+        send_stored_file($file, 10*60, 0, true); // download MUST be forced - security!
+
+    // ========================================================================================================================
+    } else if ($component === 'grade') {
+        if (($filearea === 'outcome' or $filearea === 'scale') and $context->contextlevel == CONTEXT_SYSTEM) {
+            // Global gradebook files
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+            $fullpath = "/$context->id/$component/$filearea/".implode('/', $args);
+
+            if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'feedback' and $context->contextlevel == CONTEXT_COURSE) {
+            //TODO: nobody implemented this yet in grade edit form!!
+            send_file_not_found();
+
+            if ($CFG->forcelogin || $course->id != SITEID) {
+                require_login($course);
+            }
+
+            $fullpath = "/$context->id/$component/$filearea/".implode('/', $args);
+
+            if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'tag') {
+        if ($filearea === 'description' and $context->contextlevel == CONTEXT_SYSTEM) {
+
+            // All tag descriptions are going to be public but we still need to respect forcelogin
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+            $fullpath = "/$context->id/tag/description/".implode('/', $args);
+
+            if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, true);
+
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'calendar') {
+        if ($filearea === 'event_description'  and $context->contextlevel == CONTEXT_SYSTEM) {
+
+            // All events here are public the one requirement is that we respect forcelogin
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+            // Get the event if from the args array
+            $eventid = array_shift($args);
+
+            // Load the event from the database
+            if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'eventtype'=>'site'))) {
+                send_file_not_found();
+            }
+            // Check that we got an event and that it's userid is that of the user
+
+            // Get the file and serve if successful
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_USER) {
+
+            // Must be logged in, if they are not then they obviously can't be this user
+            require_login();
+
+            // Don't want guests here, potentially saves a DB call
+            if (isguestuser()) {
+                send_file_not_found();
+            }
+
+            // Get the event if from the args array
+            $eventid = array_shift($args);
+
+            // Load the event from the database - user id must match
+            if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'userid'=>$USER->id, 'eventtype'=>'user'))) {
+                send_file_not_found();
+            }
+
+            // Get the file and serve if successful
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_COURSE) {
+
+            // Respect forcelogin and require login unless this is the site.... it probably
+            // should NEVER be the site
+            if ($CFG->forcelogin || $course->id != SITEID) {
+                require_login($course);
+            }
+
+            // Must be able to at least view the course
+            if (!is_enrolled($context) and !is_viewing($context)) {
+                //TODO: hmm, do we really want to block guests here?
+                send_file_not_found();
+            }
+
+            // Get the event id
+            $eventid = array_shift($args);
+
+            // Load the event from the database we need to check whether it is
+            // a) valid course event
+            // b) a group event
+            // Group events use the course context (there is no group context)
+            if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'courseid'=>$course->id))) {
+                send_file_not_found();
+            }
+
+            // If its a group event require either membership of view all groups capability
+            if ($event->eventtype === 'group') {
+                if (!has_capability('moodle/site:accessallgroups', $context) && !groups_is_member($event->groupid, $USER->id)) {
+                    send_file_not_found();
+                }
+            } else if ($event->eventtype === 'course') {
+                //ok
+            } else {
+                // some other type
+                send_file_not_found();
+            }
+
+            // If we get this far we can serve the file
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'user') {
+        if ($filearea === 'icon' and $context->contextlevel == CONTEXT_USER) {
+            $redirect = false;
+            if (count($args) == 1) {
+                $themename = theme_config::DEFAULT_THEME;
+                $filename = array_shift($args);
+            } else {
+                $themename = array_shift($args);
+                $filename = array_shift($args);
+            }
+            if ((!empty($CFG->forcelogin) and !isloggedin())) {
+                // protect images if login required and not logged in;
+                // do not use require_login() because it is expensive and not suitable here anyway
+                $redirect = true;
+            }
+            if (!$redirect and ($filename !== 'f1' and $filename !== 'f2')) {
+                $filename = 'f1';
+                $redirect = true;
+            }
+            if (!$redirect && !$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.png')) {
+                if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg')) {
+                    $redirect = true;
+                }
+            }
+            if ($redirect) {
+                $theme = theme_config::load($themename);
+                redirect($theme->pix_url('u/'.$filename, 'moodle'));
+            }
+            send_stored_file($file, 60*60*24); // enable long caching, there are many images on each page
+
+        } else if ($filearea === 'private' and $context->contextlevel == CONTEXT_USER) {
+            require_login();
+
+            if (isguestuser()) {
+                send_file_not_found();
+            }
+
+            if ($USER->id !== $context->instanceid) {
+                send_file_not_found();
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 0, 0, true); // must force download - security!
+
+        } else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_USER) {
+
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+            $userid = $context->instanceid;
+
+            if ($USER->id == $userid) {
+                // always can access own
+
+            } else if (!empty($CFG->forceloginforprofiles)) {
+                require_login();
+
+                if (isguestuser()) {
+                    send_file_not_found();
+                }
+
+                // we allow access to site profile of all course contacts (usually teachers)
+                if (!has_coursecontact_role($userid) && !has_capability('moodle/user:viewdetails', $context)) {
+                    send_file_not_found();
+                }
+
+                $canview = false;
+                if (has_capability('moodle/user:viewdetails', $context)) {
+                    $canview = true;
+                } else {
+                    $courses = enrol_get_my_courses();
+                }
+
+                while (!$canview && count($courses) > 0) {
+                    $course = array_shift($courses);
+                    if (has_capability('moodle/user:viewdetails', get_context_instance(CONTEXT_COURSE, $course->id))) {
+                        $canview = true;
+                    }
+                }
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 0, 0, true); // must force download - security!
+
+        } else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_COURSE) {
+            $userid = (int)array_shift($args);
+            $usercontext = get_context_instance(CONTEXT_USER, $userid);
+
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+            if (!empty($CFG->forceloginforprofiles)) {
+                require_login();
+                if (isguestuser()) {
+                    print_error('noguest');
+                }
+
+                //TODO: review this logic of user profile access prevention
+                if (!has_coursecontact_role($userid) and !has_capability('moodle/user:viewdetails', $usercontext)) {
+                    print_error('usernotavailable');
+                }
+                if (!has_capability('moodle/user:viewdetails', $context) && !has_capability('moodle/user:viewdetails', $usercontext)) {
+                    print_error('cannotviewprofile');
+                }
+                if (!is_enrolled($context, $userid)) {
+                    print_error('notenrolledprofile');
+                }
+                if (groups_get_course_groupmode($course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
+                    print_error('groupnotamember');
+                }
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($usercontext->id, 'user', 'profile', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 0, 0, true); // must force download - security!
+
+        } else if ($filearea === 'backup' and $context->contextlevel == CONTEXT_USER) {
+            require_login();
+
+            if (isguestuser()) {
+                send_file_not_found();
+            }
+            $userid = $context->instanceid;
+
+            if ($USER->id != $userid) {
+                send_file_not_found();
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'user', 'backup', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 0, 0, true); // must force download - security!
+
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'coursecat') {
+        if ($context->contextlevel != CONTEXT_COURSECAT) {
+            send_file_not_found();
+        }
+
+        if ($filearea === 'description') {
+            if ($CFG->forcelogin) {
+                // no login necessary - unless login forced everywhere
+                require_login();
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'coursecat', 'description', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'course') {
+        if ($context->contextlevel != CONTEXT_COURSE) {
+            send_file_not_found();
+        }
+
+        if ($filearea === 'summary') {
+            if ($CFG->forcelogin) {
+                require_login();
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'course', 'summary', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'section') {
+            if ($CFG->forcelogin) {
+                require_login($course);
+            } else if ($course->id != SITEID) {
+                require_login($course);
+            }
+
+            $sectionid = (int)array_shift($args);
+
+            if (!$section = $DB->get_record('course_sections', array('id'=>$sectionid, 'course'=>$course->id))) {
+                send_file_not_found();
+            }
+
+            if ($course->numsections < $section->section) {
+                if (!has_capability('moodle/course:update', $context)) {
+                    // block access to unavailable sections if can not edit course
+                    send_file_not_found();
+                }
+            }
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'course', 'section', $sectionid, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else {
+            send_file_not_found();
+        }
+
+    } else if ($component === 'group') {
+        if ($context->contextlevel != CONTEXT_COURSE) {
+            send_file_not_found();
+        }
+
+        require_course_login($course, true, null, false);
+
+        $groupid = (int)array_shift($args);
+
+        $group = $DB->get_record('groups', array('id'=>$groupid, 'courseid'=>$course->id), '*', MUST_EXIST);
+        if (($course->groupmodeforce and $course->groupmode == SEPARATEGROUPS) and !has_capability('moodle/site:accessallgroups', $context) and !groups_is_member($group->id, $USER->id)) {
+            // do not allow access to separate group info if not member or teacher
+            send_file_not_found();
+        }
+
+        if ($filearea === 'description') {
+
+            require_login($course);
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'group', 'description', $group->id, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'icon') {
+            $filename = array_pop($args);
+
+            if ($filename !== 'f1' and $filename !== 'f2') {
+                send_file_not_found();
+            }
+            if (!$file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename.'.png')) {
+                if (!$file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename.'.jpg')) {
+                    send_file_not_found();
+                }
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60);
+
+        } else {
+            send_file_not_found();
+        }
+
+    } else if ($component === 'grouping') {
+        if ($context->contextlevel != CONTEXT_COURSE) {
+            send_file_not_found();
+        }
+
+        require_login($course);
+
+        $groupingid = (int)array_shift($args);
+
+        // note: everybody has access to grouping desc images for now
+        if ($filearea === 'description') {
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'grouping', 'description', $groupingid, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'backup') {
+        if ($filearea === 'course' and $context->contextlevel == CONTEXT_COURSE) {
+            require_login($course);
+            require_capability('moodle/backup:downloadfile', $context);
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'backup', 'course', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 0, 0, $forcedownload);
+
+        } else if ($filearea === 'section' and $context->contextlevel == CONTEXT_COURSE) {
+            require_login($course);
+            require_capability('moodle/backup:downloadfile', $context);
+
+            $sectionid = (int)array_shift($args);
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'backup', 'section', $sectionid, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close();
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'activity' and $context->contextlevel == CONTEXT_MODULE) {
+            require_login($course, false, $cm);
+            require_capability('moodle/backup:downloadfile', $context);
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'backup', 'activity', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close();
+            send_stored_file($file, 60*60, 0, $forcedownload);
+
+        } else if ($filearea === 'automated' and $context->contextlevel == CONTEXT_COURSE) {
+            // Backup files that were generated by the automated backup systems.
+
+            require_login($course);
+            require_capability('moodle/site:config', $context);
+
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'backup', 'automated', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 0, 0, $forcedownload);
+
+        } else {
+            send_file_not_found();
+        }
+
+    // ========================================================================================================================
+    } else if ($component === 'question') {
+        require_once($CFG->libdir . '/questionlib.php');
+        question_pluginfile($course, $context, 'question', $filearea, $args, $forcedownload);
+        send_file_not_found();
+
+    // ========================================================================================================================
+    } else if ($component === 'grading') {
+        if ($filearea === 'description') {
+            // files embedded into the form definition description
+
+            if ($context->contextlevel == CONTEXT_SYSTEM) {
+                require_login();
+
+            } else if ($context->contextlevel >= CONTEXT_COURSE) {
+                require_login($course, false, $cm);
+
+            } else {
+                send_file_not_found();
+            }
+
+            $formid = (int)array_shift($args);
+
+            $sql = "SELECT ga.id
+                FROM {grading_areas} ga
+                JOIN {grading_definitions} gd ON (gd.areaid = ga.id)
+                WHERE gd.id = ? AND ga.contextid = ?";
+            $areaid = $DB->get_field_sql($sql, array($formid, $context->id), IGNORE_MISSING);
+
+            if (!$areaid) {
+                send_file_not_found();
+            }
+
+            $fullpath = "/$context->id/$component/$filearea/$formid/".implode('/', $args);
+
+            if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            session_get_instance()->write_close(); // unlock session during fileserving
+            send_stored_file($file, 60*60, 0, $forcedownload);
+        }
+
+        // ========================================================================================================================
+    } else if (strpos($component, 'mod_') === 0) {
+        $modname = substr($component, 4);
+        if (!file_exists("$CFG->dirroot/mod/$modname/lib.php")) {
+            send_file_not_found();
+        }
+        require_once("$CFG->dirroot/mod/$modname/lib.php");
+
+        if ($context->contextlevel == CONTEXT_MODULE) {
+            if ($cm->modname !== $modname) {
+                // somebody tries to gain illegal access, cm type must match the component!
+                send_file_not_found();
+            }
+        }
+
+        if ($filearea === 'intro') {
+            if (!plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)) {
+                send_file_not_found();
+            }
+            require_course_login($course, true, $cm);
+
+            // all users may access it
+            $filename = array_pop($args);
+            $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+            if (!$file = $fs->get_file($context->id, 'mod_'.$modname, 'intro', 0, $filepath, $filename) or $file->is_directory()) {
+                send_file_not_found();
+            }
+
+            $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
+
+            // finally send the file
+            send_stored_file($file, $lifetime, 0);
+        }
+
+        $filefunction = $component.'_pluginfile';
+        $filefunctionold = $modname.'_pluginfile';
+        if (function_exists($filefunction)) {
+            // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
+            $filefunction($course, $cm, $context, $filearea, $args, $forcedownload);
+        } else if (function_exists($filefunctionold)) {
+            // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
+            $filefunctionold($course, $cm, $context, $filearea, $args, $forcedownload);
+        }
+
+        send_file_not_found();
+
+    // ========================================================================================================================
+    } else if (strpos($component, 'block_') === 0) {
+        $blockname = substr($component, 6);
+        // note: no more class methods in blocks please, that is ....
+        if (!file_exists("$CFG->dirroot/blocks/$blockname/lib.php")) {
+            send_file_not_found();
+        }
+        require_once("$CFG->dirroot/blocks/$blockname/lib.php");
+
+        if ($context->contextlevel == CONTEXT_BLOCK) {
+            $birecord = $DB->get_record('block_instances', array('id'=>$context->instanceid), '*',MUST_EXIST);
+            if ($birecord->blockname !== $blockname) {
+                // somebody tries to gain illegal access, cm type must match the component!
+                send_file_not_found();
+            }
+        } else {
+            $birecord = null;
+        }
+
+        $filefunction = $component.'_pluginfile';
+        if (function_exists($filefunction)) {
+            // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
+            $filefunction($course, $birecord, $context, $filearea, $args, $forcedownload);
+        }
+
+        send_file_not_found();
+
+    } else if (strpos($component, '_') === false) {
+        // all core subsystems have to be specified above, no more guessing here!
+        send_file_not_found();
+
+    } else {
+        // try to serve general plugin file in arbitrary context
+        $dir = get_component_directory($component);
+        if (!file_exists("$dir/lib.php")) {
+            send_file_not_found();
+        }
+        include_once("$dir/lib.php");
+
+        $filefunction = $component.'_pluginfile';
+        if (function_exists($filefunction)) {
+            // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
+            $filefunction($course, $cm, $context, $filearea, $args, $forcedownload);
+        }
+
+        send_file_not_found();
+    }
+
+}
index 82a672e..239021b 100644 (file)
@@ -1060,7 +1060,7 @@ class global_navigation extends navigation_node {
         $mycourses = enrol_get_my_courses(NULL, 'visible DESC,sortorder ASC', $limit);
         $showallcourses = (count($mycourses) == 0 || !empty($CFG->navshowallcourses));
         $showcategories = ($showallcourses && $this->show_categories());
-        $issite = ($this->page->course->id != SITEID);
+        $issite = ($this->page->course->id == SITEID);
         $ismycourse = (array_key_exists($this->page->course->id, $mycourses));
 
         // Check if any courses were returned.
@@ -1080,143 +1080,143 @@ class global_navigation extends navigation_node {
         // JavaScript enabled.
         $frontpagecourse = $this->load_course($SITE);
         $this->add_front_page_course_essentials($frontpagecourse, $SITE);
+        $this->load_course_sections($SITE, $frontpagecourse);
 
         $canviewcourseprofile = true;
 
-        // Next load context specific content into the navigation
-        switch ($this->page->context->contextlevel) {
-            case CONTEXT_SYSTEM :
-                // This has already been loaded we just need to map the variable
-                $coursenode = $frontpagecourse;
-                $this->load_all_categories(null, $showcategories);
-                break;
-            case CONTEXT_COURSECAT :
-                // This has already been loaded we just need to map the variable
-                $coursenode = $frontpagecourse;
-                $this->load_all_categories($this->page->context->instanceid, $showcategories);
-                break;
-            case CONTEXT_BLOCK :
-            case CONTEXT_COURSE :
-                // Load the course associated with the page into the navigation
-                $course = $this->page->course;
-                if ($showcategories && !$issite && !$ismycourse) {
-                    $this->load_all_categories($course->category, $showcategories);
-                }
-                $coursenode = $this->load_course($course);
-
-                // If the course wasn't added then don't try going any further.
-                if (!$coursenode) {
-                    $canviewcourseprofile = false;
+        if (!$issite) {
+            // Next load context specific content into the navigation
+            switch ($this->page->context->contextlevel) {
+                case CONTEXT_SYSTEM :
+                    // This has already been loaded we just need to map the variable
+                    $coursenode = $frontpagecourse;
+                    $this->load_all_categories(null, $showcategories);
                     break;
-                }
-
-                // If the user is not enrolled then we only want to show the
-                // course node and not populate it.
-
-                // Not enrolled, can't view, and hasn't switched roles
-                if (!can_access_course($course)) {
-                    // TODO: very ugly hack - do not force "parents" to enrol into course their child is enrolled in,
-                    // this hack has been propagated from user/view.php to display the navigation node. (MDL-25805)
-                    $isparent = false;
-                    if ($this->useridtouseforparentchecks) {
-                        if ($this->useridtouseforparentchecks != $USER->id) {
-                            $usercontext   = get_context_instance(CONTEXT_USER, $this->useridtouseforparentchecks, MUST_EXIST);
-                            if ($DB->record_exists('role_assignments', array('userid' => $USER->id, 'contextid' => $usercontext->id))
-                                    and has_capability('moodle/user:viewdetails', $usercontext)) {
-                                $isparent = true;
-                            }
-                        }
+                case CONTEXT_COURSECAT :
+                    // This has already been loaded we just need to map the variable
+                    $coursenode = $frontpagecourse;
+                    $this->load_all_categories($this->page->context->instanceid, $showcategories);
+                    break;
+                case CONTEXT_BLOCK :
+                case CONTEXT_COURSE :
+                    // Load the course associated with the page into the navigation
+                    $course = $this->page->course;
+                    if ($showcategories && !$ismycourse) {
+                        $this->load_all_categories($course->category, $showcategories);
                     }
+                    $coursenode = $this->load_course($course);
 
-                    if (!$isparent) {
-                        $coursenode->make_active();
+                    // If the course wasn't added then don't try going any further.
+                    if (!$coursenode) {
                         $canviewcourseprofile = false;
                         break;
                     }
-                }
-                // Add the essentials such as reports etc...
-                $this->add_course_essentials($coursenode, $course);
-                if ($this->format_display_course_content($course->format)) {
-                    // Load the course sections
-                    $sections = $this->load_course_sections($course, $coursenode);
-                }
-                if (!$coursenode->contains_active_node() && !$coursenode->search_for_active_node()) {
-                    $coursenode->make_active();
-                }
-                break;
-            case CONTEXT_MODULE :
-                $course = $this->page->course;
-                $cm = $this->page->cm;
 
-                if ($showcategories && !$issite && !$ismycourse) {
-                    $this->load_all_categories($course->category, $showcategories);
-                }
+                    // If the user is not enrolled then we only want to show the
+                    // course node and not populate it.
 
-                // Load the course associated with the page into the navigation
-                $coursenode = $this->load_course($course);
+                    // Not enrolled, can't view, and hasn't switched roles
+                    if (!can_access_course($course)) {
+                        // TODO: very ugly hack - do not force "parents" to enrol into course their child is enrolled in,
+                        // this hack has been propagated from user/view.php to display the navigation node. (MDL-25805)
+                        $isparent = false;
+                        if ($this->useridtouseforparentchecks) {
+                            if ($this->useridtouseforparentchecks != $USER->id) {
+                                $usercontext   = get_context_instance(CONTEXT_USER, $this->useridtouseforparentchecks, MUST_EXIST);
+                                if ($DB->record_exists('role_assignments', array('userid' => $USER->id, 'contextid' => $usercontext->id))
+                                        and has_capability('moodle/user:viewdetails', $usercontext)) {
+                                    $isparent = true;
+                                }
+                            }
+                        }
 
-                // If the course wasn't added then don't try going any further.
-                if (!$coursenode) {
-                    $canviewcourseprofile = false;
+                        if (!$isparent) {
+                            $coursenode->make_active();
+                            $canviewcourseprofile = false;
+                            break;
+                        }
+                    }
+                    // Add the essentials such as reports etc...
+                    $this->add_course_essentials($coursenode, $course);
+                    if ($this->format_display_course_content($course->format)) {
+                        // Load the course sections
+                        $sections = $this->load_course_sections($course, $coursenode);
+                    }
+                    if (!$coursenode->contains_active_node() && !$coursenode->search_for_active_node()) {
+                        $coursenode->make_active();
+                    }
                     break;
-                }
+                case CONTEXT_MODULE :
+                    $course = $this->page->course;
+                    $cm = $this->page->cm;
 
-                // If the user is not enrolled then we only want to show the
-                // course node and not populate it.
-                if (!can_access_course($course)) {
-                    $coursenode->make_active();
-                    $canviewcourseprofile = false;
-                    break;
-                }
+                    if ($showcategories && !$ismycourse) {
+                        $this->load_all_categories($course->category, $showcategories);
+                    }
 
-                $this->add_course_essentials($coursenode, $course);
-                // Load the course sections into the page
-                $sections = $this->load_course_sections($course, $coursenode);
-                if ($course->id != SITEID) {
-                    // Find the section for the $CM associated with the page and collect
-                    // its section number.
-                    if (isset($cm->sectionnum)) {
-                        $cm->sectionnumber = $cm->sectionnum;
-                    } else {
-                        foreach ($sections as $section) {
-                            if ($section->id == $cm->section) {
-                                $cm->sectionnumber = $section->section;
-                                break;
+                    // Load the course associated with the page into the navigation
+                    $coursenode = $this->load_course($course);
+
+                    // If the course wasn't added then don't try going any further.
+                    if (!$coursenode) {
+                        $canviewcourseprofile = false;
+                        break;
+                    }
+
+                    // If the user is not enrolled then we only want to show the
+                    // course node and not populate it.
+                    if (!can_access_course($course)) {
+                        $coursenode->make_active();
+                        $canviewcourseprofile = false;
+                        break;
+                    }
+
+                    $this->add_course_essentials($coursenode, $course);
+                    // Load the course sections into the page
+                    $sections = $this->load_course_sections($course, $coursenode);
+                    if ($course->id != SITEID) {
+                        // Find the section for the $CM associated with the page and collect
+                        // its section number.
+                        if (isset($cm->sectionnum)) {
+                            $cm->sectionnumber = $cm->sectionnum;
+                        } else {
+                            foreach ($sections as $section) {
+                                if ($section->id == $cm->section) {
+                                    $cm->sectionnumber = $section->section;
+                                    break;
+                                }
                             }
                         }
-                    }
 
-                    // Load all of the section activities for the section the cm belongs to.
-                    if (isset($cm->sectionnumber) and !empty($sections[$cm->sectionnumber])) {
-                        list($sectionarray, $activityarray) = $this->generate_sections_and_activities($course);
-                        $activities = $this->load_section_activities($sections[$cm->sectionnumber]->sectionnode, $cm->sectionnumber, $activityarray);
+                        // Load all of the section activities for the section the cm belongs to.
+                        if (isset($cm->sectionnumber) and !empty($sections[$cm->sectionnumber])) {
+                            list($sectionarray, $activityarray) = $this->generate_sections_and_activities($course);
+                            $activities = $this->load_section_activities($sections[$cm->sectionnumber]->sectionnode, $cm->sectionnumber, $activityarray);
+                        } else {
+                            $activities = array();
+                            if ($activity = $this->load_stealth_activity($coursenode, get_fast_modinfo($course))) {
+                                // "stealth" activity from unavailable section
+                                $activities[$cm->id] = $activity;
+                            }
+                        }
                     } else {
                         $activities = array();
-                        if ($activity = $this->load_stealth_activity($coursenode, get_fast_modinfo($course))) {
-                            // "stealth" activity from unavailable section
-                            $activities[$cm->id] = $activity;
-                        }
+                        $activities[$cm->id] = $coursenode->get($cm->id, navigation_node::TYPE_ACTIVITY);
                     }
-                } else {
-                    $activities = array();
-                    $activities[$cm->id] = $coursenode->get($cm->id, navigation_node::TYPE_ACTIVITY);
-                }
-                if (!empty($activities[$cm->id])) {
-                    // Finally load the cm specific navigaton information
-                    $this->load_activity($cm, $course, $activities[$cm->id]);
-                    // Check if we have an active ndoe
-                    if (!$activities[$cm->id]->contains_active_node() && !$activities[$cm->id]->search_for_active_node()) {
-                        // And make the activity node active.
-                        $activities[$cm->id]->make_active();
+                    if (!empty($activities[$cm->id])) {
+                        // Finally load the cm specific navigaton information
+                        $this->load_activity($cm, $course, $activities[$cm->id]);
+                        // Check if we have an active ndoe
+                        if (!$activities[$cm->id]->contains_active_node() && !$activities[$cm->id]->search_for_active_node()) {
+                            // And make the activity node active.
+                            $activities[$cm->id]->make_active();
+                        }
+                    } else {
+                        //TODO: something is wrong, what to do? (Skodak)
                     }
-                } else {
-                    //TODO: something is wrong, what to do? (Skodak)
-                }
-                break;
-            case CONTEXT_USER :
-                $course = $this->page->course;
-                if ($course->id != SITEID) {
-                    if ($showcategories && !$issite && !$ismycourse) {
+                    break;
+                case CONTEXT_USER :
+                    if ($showcategories && !$ismycourse) {
                         $this->load_all_categories($course->category, $showcategories);
                     }
                     // Load the course associated with the user into the navigation
@@ -1237,8 +1237,8 @@ class global_navigation extends navigation_node {
                     }
                     $this->add_course_essentials($coursenode, $course);
                     $sections = $this->load_course_sections($course, $coursenode);
-                }
-                break;
+                    break;
+            }
         }
 
         $limit = 20;
index 3a1dc07..c5c2046 100644 (file)
@@ -104,7 +104,7 @@ class user_picture implements renderable {
     /**
      * @var array List of mandatory fields in user record here. (do not include TEXT columns because it would break SELECT DISTINCT in MSSQL and ORACLE)
      */
-    protected static $fields = array('id', 'picture', 'firstname', 'lastname', 'imagealt', 'email');
+    protected static $fields = array('id', 'picture', 'firstname', 'lastname', 'imagealt', 'email'); //TODO: add deleted
 
     /**
      * @var object $user A user object with at least fields all columns specified in $fields array constant set.
@@ -300,9 +300,12 @@ class user_picture implements renderable {
 
         // First we need to determine whether the user has uploaded a profile
         // picture of not.
-        $fs = get_file_storage();
-        $context = get_context_instance(CONTEXT_USER, $this->user->id);
-        $hasuploadedfile = ($fs->file_exists($context->id, 'user', 'icon', 0, '/', $filename.'/.png') || $fs->file_exists($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg'));
+        if (!empty($this->user->deleted) or !$context = context_user::instance($this->user->id, IGNORE_MISSING)) {
+            $hasuploadedfile = false;
+        } else {
+            $fs = get_file_storage();
+            $hasuploadedfile = ($fs->file_exists($context->id, 'user', 'icon', 0, '/', $filename.'/.png') || $fs->file_exists($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg'));
+        }
 
         $imageurl = $renderer->pix_url('u/'.$filename);
         if ($hasuploadedfile && $this->user->picture == 1) {
index a624a4d..f8f3af8 100644 (file)
@@ -10,6 +10,7 @@ removed unused libraries:
 API changes:
 * new admin/tool plugin type
 * new context API - old API is still available
+* deleted users do not have context any more
 * removed global search
 
 
index 356ac17..7d10cd9 100644 (file)
@@ -34,7 +34,6 @@
 
 #page-mod-assignment-submissions .mform.optionspref .fitem .fitemtitle {width:50%;}
 #page-mod-assignment-submissions .mform.optionspref .fitem .felement {width: 30%; margin-left: 51%;}
-#page-mod-assignment-submissions.dir-rtl .mform .fitem .felement {margin-right: 51%; margin-left: 0;}
 
 #page-mod-assignment-submissions .optionspref {width: 50%;}
 #page-mod-assignment-submissions .fastgbutton {text-align: center;}
index aaee017..c7598c8 100644 (file)
@@ -348,3 +348,36 @@ function folder_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-folder-*'=>get_string('page-mod-folder-x', 'folder'));
     return $module_pagetype;
 }
+
+/**
+ * Export folder resource contents
+ *
+ * @return array of file content
+ */
+function folder_export_contents($cm, $baseurl) {
+    global $CFG, $DB;
+    $contents = array();
+    $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+    $folder = $DB->get_record('folder', array('id'=>$cm->instance), '*', MUST_EXIST);
+
+    $fs = get_file_storage();
+    $files = $fs->get_area_files($context->id, 'mod_folder', 'content', 0, 'sortorder DESC, id ASC', false);
+
+    foreach ($files as $fileinfo) {
+        $file = array();
+        $file['type'] = 'file';
+        $file['filename']     = $fileinfo->get_filename();
+        $file['filepath']     = $fileinfo->get_filepath();
+        $file['filesize']     = $fileinfo->get_filesize();
+        $file['fileurl']      = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_folder/content/'.$folder->revision.$fileinfo->get_filepath().$fileinfo->get_filename(), true);
+        $file['timecreated']  = $fileinfo->get_timecreated();
+        $file['timemodified'] = $fileinfo->get_timemodified();
+        $file['sortorder']    = $fileinfo->get_sortorder();
+        $file['userid']       = $fileinfo->get_userid();
+        $file['author']       = $fileinfo->get_author();
+        $file['license']      = $fileinfo->get_license();
+        $contents[] = $file;
+    }
+
+    return $contents;
+}
index 18f054b..0ec460b 100644 (file)
@@ -68,7 +68,6 @@ $strunsubscribe  = get_string('unsubscribe', 'forum');
 $stryes          = get_string('yes');
 $strno           = get_string('no');
 $strrss          = get_string('rss');
-$strsectionname  = get_string('sectionname', 'format_'.$course->format);
 
 $searchform = forum_search_form($course);
 
@@ -260,8 +259,14 @@ if ($generalforums) {
                 } else {
                     $tooltiptext = get_string('rsssubscriberssposts', 'forum');
                 }
+
+                if (!isloggedin() && $course->id == SITEID) {
+                    $userid = guest_user()->id;
+                } else {
+                    $userid = $USER->id;
+                }
                 //Get html code for RSS link
-                $row[] = rss_get_link($context->id, $USER->id, 'mod_forum', $forum->id, $tooltiptext);
+                $row[] = rss_get_link($context->id, $userid, 'mod_forum', $forum->id, $tooltiptext);
             } else {
                 $row[] = '&nbsp;';
             }
@@ -300,6 +305,8 @@ if ($show_rss = (($can_subscribe || $course->id == SITEID) &&
 /// Now let's process the learning forums
 
 if ($course->id != SITEID) {    // Only real courses have learning forums
+    // 'format_.'$course->format only applicable when not SITEID (format_site is not a format)
+    $strsectionname  = get_string('sectionname', 'format_'.$course->format);
     // Add extra field for section number, at the front
     array_unshift($learningtable->head, $strsectionname);
     array_unshift($learningtable->align, 'center');
@@ -410,7 +417,7 @@ $PAGE->set_heading($course->fullname);
 $PAGE->set_button($searchform);
 echo $OUTPUT->header();
 
-if (!isguestuser()) {
+if (!isguestuser() && isloggedin()) {
     echo $OUTPUT->box_start('subscription');
     echo html_writer::tag('div',
         html_writer::link(new moodle_url('/mod/forum/index.php', array('id'=>$course->id, 'subscribe'=>1, 'sesskey'=>sesskey())),
index 48344e4..798bc22 100644 (file)
@@ -4012,6 +4012,72 @@ function forum_get_file_areas($course, $cm, $context) {
     return $areas;
 }
 
+/**
+ * File browsing support for forum module.
+ *
+ * @param object $browser
+ * @param object $areas
+ * @param object $course
+ * @param object $cm
+ * @param object $context
+ * @param string $filearea
+ * @param int $itemid
+ * @param string $filepath
+ * @param string $filename
+ * @return object file_info instance or null if not found
+ */
+function forum_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
+    global $CFG, $DB;
+
+    if ($context->contextlevel != CONTEXT_MODULE) {
+        return null;
+    }
+
+    $fileareas = array('attachment', 'post');
+    if (!in_array($filearea, $fileareas)) {
+        return null;
+    }
+
+    if (!$post = $DB->get_record('forum_posts', array('id' => $itemid))) {
+        return null;
+    }
+
+    if (!$discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
+        return null;
+    }
+
+    if (!$forum = $DB->get_record('forum', array('id' => $cm->instance))) {
+        return null;
+    }
+
+    $fs = get_file_storage();
+    $filepath = is_null($filepath) ? '/' : $filepath;
+    $filename = is_null($filename) ? '.' : $filename;
+    if (!($storedfile = $fs->get_file($context->id, 'mod_forum', $filearea, $itemid, $filepath, $filename))) {
+        return null;
+    }
+
+    // Make sure groups allow this user to see this file
+    if ($discussion->groupid > 0 and $groupmode = groups_get_activity_groupmode($cm, $course)) {   // Groups are being used
+        if (!groups_group_exists($discussion->groupid)) { // Can't find group
+            return null;                           // Be safe and don't send it to anyone
+        }
+
+        if (!groups_is_member($discussion->groupid) and !has_capability('moodle/site:accessallgroups', $context)) {
+            // do not send posts from other groups when in SEPARATEGROUPS or VISIBLEGROUPS
+            return null;
+        }
+    }
+
+    // Make sure we're allowed to see it...
+    if (!forum_user_can_see_post($forum, $discussion, $post, NULL, $cm)) {
+        return null;
+    }
+
+    $urlbase = $CFG->wwwroot.'/pluginfile.php';
+    return new file_info_stored($browser, $context, $storedfile, $urlbase, $filearea, $itemid, true, true, false);
+}
+
 /**
  * Serves the forum attachments. Implements needed access control ;-)
  *
@@ -4834,6 +4900,10 @@ function forum_user_can_post_discussion($forum, $currentgroup=null, $unused=-1,
         return false;
     }
 
+    if ($forum->type == 'single') {
+        return false;
+    }
+
     if ($forum->type == 'eachuser') {
         if (forum_user_has_posted_discussion($forum->id, $USER->id)) {
             return false;
@@ -7430,7 +7500,16 @@ function forum_extend_settings_navigation(settings_navigation $settingsnav, navi
         }
     }
 
-    if ($enrolled && !empty($CFG->enablerssfeeds) && !empty($CFG->forum_enablerssfeeds) && $forumobject->rsstype && $forumobject->rssarticles) {
+    if (!isloggedin() && $PAGE->course->id == SITEID) {
+        $userid = guest_user()->id;
+    } else {
+        $userid = $USER->id;
+    }
+
+    $hascourseaccess = ($PAGE->course->id == SITEID) || can_access_course($PAGE->course, $userid);
+    $enablerssfeeds = !empty($CFG->enablerssfeeds) && !empty($CFG->forum_enablerssfeeds);
+
+    if ($enablerssfeeds && $forumobject->rsstype && $forumobject->rssarticles && $hascourseaccess) {
 
         if (!function_exists('rss_get_url')) {
             require_once("$CFG->libdir/rsslib.php");
@@ -7441,11 +7520,7 @@ function forum_extend_settings_navigation(settings_navigation $settingsnav, navi
         } else {
             $string = get_string('rsssubscriberssposts','forum');
         }
-        if (!isloggedin()) {
-            $userid = 0;
-        } else {
-            $userid = $USER->id;
-        }
+
         $url = new moodle_url(rss_get_url($PAGE->cm->context->id, $userid, "mod_forum", $forumobject->id));
         $forumnode->add($string, $url, settings_navigation::TYPE_SETTING, null, null, new pix_icon('i/rss', ''));
     }
index 43e6340..3dc672f 100644 (file)
@@ -83,6 +83,15 @@ echo $OUTPUT->header();
 $fmtoptions = array(
     'context' => $context);
 
+if (right_to_left()) { // RTL table alignment support
+    $rightalignment = 'left';
+    $leftalignment = 'right';
+} else {
+    $rightalignment = 'right';
+    $leftalignment = 'left';
+
+}
+
 if ( $hook >0 ) {
 
     if ( $action == "edit" ) {
@@ -135,7 +144,7 @@ if ( $hook >0 ) {
 
                 <table border="0" width="100" class="confirmbuttons">
                     <tr>
-                        <td align="right" style="width:50%">
+                        <td align="$rightalignment" style="width:50%">
                         <form id="form" method="post" action="editcategories.php">
                         <div>
                         <input type="hidden" name="id"          value="<?php p($cm->id) ?>" />
@@ -147,7 +156,7 @@ if ( $hook >0 ) {
                         </div>
                         </form>
                         </td>
-                        <td align="left" style="width:50%">
+                        <td align="$leftalignment" style="width:50%">
 
 <?php
             unset($options);
@@ -217,7 +226,7 @@ if ( $action ) {
 ?>
 
              <tr>
-               <td style="width:80%" align="left">
+               <td style="width:80%" align="$leftalignment">
                <?php
                     echo "<span class=\"bold\">".format_string($category->name, true, $fmtoptions)."</span> <span>($num_entries " . get_string("entries","glossary") . ")</span>";
                ?>
@@ -245,9 +254,9 @@ if ( $action ) {
              $options['id'] = $cm->id;
              $options['action'] = "add";
 
-             echo "<table class=\"editbuttons\" border=\"0\"><tr><td align=\"right\">";
+             echo "<table class=\"editbuttons\" border=\"0\"><tr><td align=\"$rightalignment\">";
              echo $OUTPUT->single_button(new moodle_url("editcategories.php", $options), get_string("add") . " " . get_string("category","glossary"));
-             echo "</td><td align=\"left\">";
+             echo "</td><td align=\"$leftalignment\">";
              unset($options['action']);
              $options['mode'] = 'cat';
              $options['hook'] = $hook;
index e5920d5..428099b 100644 (file)
@@ -83,8 +83,10 @@ function handleOAuthBodyPOST($oauth_consumer_key, $oauth_consumer_secret, $body,
     }
 
     // Must reject application/x-www-form-urlencoded
-    if ($request_headers['Content-type'] == 'application/x-www-form-urlencoded' ) {
-        throw new Exception("OAuth request body signing must not use application/x-www-form-urlencoded");
+    if (isset($request_headers['Content-type'])) {
+        if ($request_headers['Content-type'] == 'application/x-www-form-urlencoded' ) {
+            throw new Exception("OAuth request body signing must not use application/x-www-form-urlencoded");
+        }
     }
 
     if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
index 34a2674..aaeeb42 100644 (file)
@@ -70,7 +70,13 @@ class lti_locallib_test extends UnitTestCase {
                 array('custom_complex____________key' => 'Complex!@#$^*(){}[]Value'));
     }
 
-    public function test_sign_parameters() {
+    /**
+     * This test has been disabled because the test-tool is
+     * being moved and probably it won't work anymore for this.
+     * We should be testing here local stuff only and leave
+     * outside-checks to the conformance tests. MDL-30347
+     */
+    public function disabled_test_sign_parameters() {
         $correct = array ( 'context_id' => '12345', 'context_label' => 'SI124', 'context_title' => 'Social Computing', 'ext_submit' => 'Click Me', 'lti_message_type' => 'basic-lti-launch-request', 'lti_version' => 'LTI-1p0', 'oauth_consumer_key' => 'lmsng.school.edu', 'oauth_nonce' => '47458148e33a8f9dafb888c3684cf476', 'oauth_signature' => 'qWgaBIezihCbeHgcwUy14tZcyDQ=', 'oauth_signature_method' => 'HMAC-SHA1', 'oauth_timestamp' => '1307141660', 'oauth_version' => '1.0', 'resource_link_id' => '123', 'resource_link_title' => 'Weekly Blog', 'roles' => 'Learner', 'tool_consumer_instance_guid' => 'lmsng.school.edu', 'user_id' => '789');
 
         $requestparams = array('resource_link_id' => '123', 'resource_link_title' => 'Weekly Blog', 'user_id' => '789', 'roles' => 'Learner', 'context_id' => '12345', 'context_label' => 'SI124', 'context_title' => 'Social Computing');
@@ -90,7 +96,13 @@ class lti_locallib_test extends UnitTestCase {
         $this->assertEqual($parms, $correct);
     }
 
-    public function test_parse_grade_replace_message() {
+    /**
+     * This test has been disabled because, since its creation,
+     * the sourceId generation has changed and surely this is outdated.
+     * Some day these should be replaced by proper tests, but until then
+     * conformance tests say this is working. MDL-30347
+     */
+    public function disabled_test_parse_grade_replace_message() {
         $message = '
             <imsx_POXEnvelopeRequest xmlns = "http://www.imsglobal.org/lis/oms1p0/pox">
               <imsx_POXHeader>
index bfa5115..ef3d84b 100644 (file)
@@ -369,26 +369,46 @@ function page_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa
         return false;
     }
 
-    array_shift($args); // ignore revision - designed to prevent caching problems only
+    // $arg could be revision number or index.html
+    $arg = array_shift($args);
+    if ($arg == 'index.html' || $arg == 'index.htm') {
+        // serve page content
+        $filename = $arg;
 
-    $fs = get_file_storage();
-    $relativepath = implode('/', $args);
-    $fullpath = "/$context->id/mod_page/$filearea/0/$relativepath";
-    if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
-        $page = $DB->get_record('page', array('id'=>$cm->instance), 'id, legacyfiles', MUST_EXIST);
-        if ($page->legacyfiles != RESOURCELIB_LEGACYFILES_ACTIVE) {
+        if (!$page = $DB->get_record('page', array('id'=>$cm->instance), '*', MUST_EXIST)) {
             return false;
         }
-        if (!$file = resourcelib_try_file_migration('/'.$relativepath, $cm->id, $cm->course, 'mod_page', 'content', 0)) {
-            return false;
+
+        // remove @@PLUGINFILE@@/
+        $content = str_replace('@@PLUGINFILE@@/', '', $page->content);
+
+        $formatoptions = new stdClass;
+        $formatoptions->noclean = true;
+        $formatoptions->overflowdiv = true;
+        $formatoptions->context = $context;
+        $content = format_text($content, $page->contentformat, $formatoptions);
+
+        send_file($content, $filename, 0, 0, true, true);
+    } else {
+        $fs = get_file_storage();
+        $relativepath = implode('/', $args);
+        $fullpath = "/$context->id/mod_page/$filearea/0/$relativepath";
+        if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+            $page = $DB->get_record('page', array('id'=>$cm->instance), 'id, legacyfiles', MUST_EXIST);
+            if ($page->legacyfiles != RESOURCELIB_LEGACYFILES_ACTIVE) {
+                return false;
+            }
+            if (!$file = resourcelib_try_file_migration('/'.$relativepath, $cm->id, $cm->course, 'mod_page', 'content', 0)) {
+                return false;
+            }
+            //file migrate - update flag
+            $page->legacyfileslast = time();
+            $DB->update_record('page', $page);
         }
-        //file migrate - update flag
-        $page->legacyfileslast = time();
-        $DB->update_record('page', $page);
-    }
 
-    // finally send the file
-    send_stored_file($file, 86400, 0, $forcedownload);
+        // finally send the file
+        send_stored_file($file, 86400, 0, $forcedownload);
+    }
 }
 
 
@@ -422,3 +442,54 @@ function page_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-page-*'=>get_string('page-mod-page-x', 'page'));
     return $module_pagetype;
 }
+
+/**
+ * Export page resource contents
+ *
+ * @return array of file content
+ */
+function page_export_contents($cm, $baseurl) {
+    global $CFG, $DB;
+    $contents = array();
+    $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+
+    $page = $DB->get_record('page', array('id'=>$cm->instance), '*', MUST_EXIST);
+
+    // page contents
+    $fs = get_file_storage();
+    $files = $fs->get_area_files($context->id, 'mod_page', 'content', 0, 'sortorder DESC, id ASC', false);
+    foreach ($files as $fileinfo) {
+        $file = array();
+        $file['type']         = 'file';
+        $file['filename']     = $fileinfo->get_filename();
+        $file['filepath']     = $fileinfo->get_filepath();
+        $file['filesize']     = $fileinfo->get_filesize();
+        $file['fileurl']      = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_page/content/'.$page->revision.$fileinfo->get_filepath().$fileinfo->get_filename(), true);
+        $file['timecreated']  = $fileinfo->get_timecreated();
+        $file['timemodified'] = $fileinfo->get_timemodified();
+        $file['sortorder']    = $fileinfo->get_sortorder();
+        $file['userid']       = $fileinfo->get_userid();
+        $file['author']       = $fileinfo->get_author();
+        $file['license']      = $fileinfo->get_license();
+        $contents[] = $file;
+    }
+
+    // page html conent
+    $filename = 'index.html';
+    $pagefile = array();
+    $pagefile['type']         = 'file';
+    $pagefile['filename']     = $filename;
+    $pagefile['filepath']     = '/';
+    $pagefile['filesize']     = 0;
+    $pagefile['fileurl']      = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_page/content/' . $filename, true);
+    $pagefile['timecreated']  = null;
+    $pagefile['timemodified'] = $page->timemodified;
+    // make this file as main file
+    $pagefile['sortorder']    = 1;
+    $pagefile['userid']       = null;
+    $pagefile['author']       = null;
+    $pagefile['license']      = null;
+    $contents[] = $pagefile;
+
+    return $contents;
+}
index 341e588..44afba3 100644 (file)
@@ -446,3 +446,36 @@ function resource_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-resource-*'=>get_string('page-mod-resource-x', 'resource'));
     return $module_pagetype;
 }
+
+/**
+ * Export file resource contents
+ *
+ * @return array of file content
+ */
+function resource_export_contents($cm, $baseurl) {
+    global $CFG, $DB;
+    $contents = array();
+    $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+    $resource = $DB->get_record('resource', array('id'=>$cm->instance), '*', MUST_EXIST);
+
+    $fs = get_file_storage();
+    $files = $fs->get_area_files($context->id, 'mod_resource', 'content', 0, 'sortorder DESC, id ASC', false);
+
+    foreach ($files as $fileinfo) {
+        $file = array();
+        $file['type'] = 'file';
+        $file['filename']     = $fileinfo->get_filename();
+        $file['filepath']     = $fileinfo->get_filepath();
+        $file['filesize']     = $fileinfo->get_filesize();
+        $file['fileurl']      = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_resource/content/'.$resource->revision.$fileinfo->get_filepath().$fileinfo->get_filename(), true);
+        $file['timecreated']  = $fileinfo->get_timecreated();
+        $file['timemodified'] = $fileinfo->get_timemodified();
+        $file['sortorder']    = $fileinfo->get_sortorder();
+        $file['userid']       = $fileinfo->get_userid();
+        $file['author']       = $fileinfo->get_author();
+        $file['license']      = $fileinfo->get_license();
+        $contents[] = $file;
+    }
+
+    return $contents;
+}
index 322ede9..96e1ff2 100644 (file)
@@ -153,7 +153,7 @@ class scorm_interactions_report extends scorm_default_report {
             }
 
             $params = array();
-            list($usql, $params) = $DB->get_in_or_equal($allowedlist);
+            list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED);
                                     // Construct the SQL
             $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
             $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' .
index 2adb15e..f40d3d4 100644 (file)
@@ -35,7 +35,7 @@
     $notes   = optional_param('notes', '', PARAM_RAW);    // Save teachers notes
 
     $qids = explode(',', $qid);
-    $qids = clean_param($qids, PARAM_INT);
+    $qids = clean_param_array($qids, PARAM_INT);
     $qid = implode (',', $qids);
 
     if (! $cm = get_coursemodule_from_id('survey', $id)) {
index c49fd40..f8400e2 100644 (file)
@@ -329,3 +329,40 @@ function url_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-url-*'=>get_string('page-mod-url-x', 'url'));
     return $module_pagetype;
 }
+
+/**
+ * Export URL resource contents
+ *
+ * @return array of file content
+ */
+function url_export_contents($cm, $baseurl) {
+    global $CFG, $DB;
+    require_once("$CFG->dirroot/mod/url/locallib.php");
+    $contents = array();
+    $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+
+    $course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
+    $url = $DB->get_record('url', array('id'=>$cm->instance), '*', MUST_EXIST);
+
+    $fullurl = str_replace('&amp;', '&', url_get_full_url($url, $cm, $course));
+    $isurl = clean_param($fullurl, PARAM_URL);
+    if (empty($isurl)) {
+        return null;
+    }
+
+    $url = array();
+    $url['type'] = 'url';
+    $url['filename']     = $url->name;
+    $url['filepath']     = null;
+    $url['filesize']     = 0;
+    $url['fileurl']      = $fullurl;
+    $url['timecreated']  = null;
+    $url['timemodified'] = $url->timemodified;
+    $url['sortorder']    = null;
+    $url['userid']       = null;
+    $url['author']       = null;
+    $url['license']      = null;
+    $contents[] = $url;
+
+    return $contents;
+}
index 448c943..6f02035 100644 (file)
@@ -121,7 +121,7 @@ function url_get_full_url($url, $cm, $course, $config=null) {
             if (stripos($fullurl, 'teamspeak://') === 0) {
                 $fullurl = $fullurl.'?'.implode('?', $parameters);
             } else {
-                $join = (strpos($fullurl->externalurl, '?') === false) ? '?' : '&';
+                $join = (strpos($fullurl, '?') === false) ? '?' : '&';
                 $fullurl = $fullurl.$join.implode('&', $parameters);
             }
         }
index 8a73529..b121f8c 100644 (file)
@@ -70,7 +70,7 @@ class mod_wiki_edit_form extends moodleform {
             foreach ($tree['files'] as $file) {
                 $filename = $file->get_filename();
                 foreach ($extensions as $ext) {
-                    if (preg_match('#'.$ext.'$#', $filename)) {
+                    if (preg_match('#'.$ext.'$#i', $filename)) {
                         $files[] = $filename;
                     }
                 }
index 974d23e..fd187ce 100644 (file)
@@ -34,753 +34,4 @@ require_once('lib/filelib.php');
 $relativepath = get_file_argument();
 $forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
 
-// relative path must start with '/'
-if (!$relativepath) {
-    print_error('invalidargorconf');
-} else if ($relativepath[0] != '/') {
-    print_error('pathdoesnotstartslash');
-}
-
-// extract relative path components
-$args = explode('/', ltrim($relativepath, '/'));
-
-if (count($args) < 3) { // always at least context, component and filearea
-    print_error('invalidarguments');
-}
-
-$contextid = (int)array_shift($args);
-$component = clean_param(array_shift($args), PARAM_COMPONENT);
-$filearea  = clean_param(array_shift($args), PARAM_AREA);
-
-list($context, $course, $cm) = get_context_info_array($contextid);
-
-$fs = get_file_storage();
-
-// ========================================================================================================================
-if ($component === 'blog') {
-    // Blog file serving
-    if ($context->contextlevel != CONTEXT_SYSTEM) {
-        send_file_not_found();
-    }
-    if ($filearea !== 'attachment' and $filearea !== 'post') {
-        send_file_not_found();
-    }
-
-    if (empty($CFG->bloglevel)) {
-        print_error('siteblogdisable', 'blog');
-    }
-
-    if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) {
-        require_login();
-        if (isguestuser()) {
-            print_error('noguest');
-        }
-        if ($CFG->bloglevel == BLOG_USER_LEVEL) {
-            if ($USER->id != $entry->userid) {
-                send_file_not_found();
-            }
-        }
-    }
-    $entryid = (int)array_shift($args);
-    if (!$entry = $DB->get_record('post', array('module'=>'blog', 'id'=>$entryid))) {
-        send_file_not_found();
-    }
-
-    if ('publishstate' === 'public') {
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-    } else if ('publishstate' === 'site') {
-        require_login();
-        //ok
-    } else if ('publishstate' === 'draft') {
-        require_login();
-        if ($USER->id != $entry->userid) {
-            send_file_not_found();
-        }
-    }
-
-    $filename = array_pop($args);
-    $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-
-    if (!$file = $fs->get_file($context->id, $component, $filearea, $entryid, $filepath, $filename) or $file->is_directory()) {
-        send_file_not_found();
-    }
-
-    send_stored_file($file, 10*60, 0, true); // download MUST be forced - security!
-
-// ========================================================================================================================
-} else if ($component === 'grade') {
-    if (($filearea === 'outcome' or $filearea === 'scale') and $context->contextlevel == CONTEXT_SYSTEM) {
-        // Global gradebook files
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-        $fullpath = "/$context->id/$component/$filearea/".implode('/', $args);
-
-        if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'feedback' and $context->contextlevel == CONTEXT_COURSE) {
-        //TODO: nobody implemented this yet in grade edit form!!
-        send_file_not_found();
-
-        if ($CFG->forcelogin || $course->id != SITEID) {
-            require_login($course);
-        }
-
-        $fullpath = "/$context->id/$component/$filearea/".implode('/', $args);
-
-        if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'tag') {
-    if ($filearea === 'description' and $context->contextlevel == CONTEXT_SYSTEM) {
-
-        // All tag descriptions are going to be public but we still need to respect forcelogin
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-        $fullpath = "/$context->id/tag/description/".implode('/', $args);
-
-        if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, true);
-
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'calendar') {
-    if ($filearea === 'event_description'  and $context->contextlevel == CONTEXT_SYSTEM) {
-
-        // All events here are public the one requirement is that we respect forcelogin
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-        // Get the event if from the args array
-        $eventid = array_shift($args);
-
-        // Load the event from the database
-        if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'eventtype'=>'site'))) {
-            send_file_not_found();
-        }
-        // Check that we got an event and that it's userid is that of the user
-
-        // Get the file and serve if successful
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_USER) {
-
-        // Must be logged in, if they are not then they obviously can't be this user
-        require_login();
-
-        // Don't want guests here, potentially saves a DB call
-        if (isguestuser()) {
-            send_file_not_found();
-        }
-
-        // Get the event if from the args array
-        $eventid = array_shift($args);
-
-        // Load the event from the database - user id must match
-        if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'userid'=>$USER->id, 'eventtype'=>'user'))) {
-            send_file_not_found();
-        }
-
-        // Get the file and serve if successful
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'event_description' and $context->contextlevel == CONTEXT_COURSE) {
-
-        // Respect forcelogin and require login unless this is the site.... it probably
-        // should NEVER be the site
-        if ($CFG->forcelogin || $course->id != SITEID) {
-            require_login($course);
-        }
-
-        // Must be able to at least view the course
-        if (!is_enrolled($context) and !is_viewing($context)) {
-            //TODO: hmm, do we really want to block guests here?
-            send_file_not_found();
-        }
-
-        // Get the event id
-        $eventid = array_shift($args);
-
-        // Load the event from the database we need to check whether it is
-        // a) valid course event
-        // b) a group event
-        // Group events use the course context (there is no group context)
-        if (!$event = $DB->get_record('event', array('id'=>(int)$eventid, 'courseid'=>$course->id))) {
-            send_file_not_found();
-        }
-
-        // If its a group event require either membership of view all groups capability
-        if ($event->eventtype === 'group') {
-            if (!has_capability('moodle/site:accessallgroups', $context) && !groups_is_member($event->groupid, $USER->id)) {
-                send_file_not_found();
-            }
-        } else if ($event->eventtype === 'course') {
-            //ok
-        } else {
-            // some other type
-            send_file_not_found();
-        }
-
-        // If we get this far we can serve the file
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, $component, $filearea, $eventid, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'user') {
-    if ($filearea === 'icon' and $context->contextlevel == CONTEXT_USER) {
-        $redirect = false;
-        if (count($args) == 1) {
-            $themename = theme_config::DEFAULT_THEME;
-            $filename = array_shift($args);
-        } else {
-            $themename = array_shift($args);
-            $filename = array_shift($args);
-        }
-        if ((!empty($CFG->forcelogin) and !isloggedin())) {
-            // protect images if login required and not logged in;
-            // do not use require_login() because it is expensive and not suitable here anyway
-            $redirect = true;
-        }
-        if (!$redirect and ($filename !== 'f1' and $filename !== 'f2')) {
-            $filename = 'f1';
-            $redirect = true;
-        }
-        if (!$redirect && !$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.png')) {
-            if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg')) {
-                $redirect = true;
-            }
-        }
-        if ($redirect) {
-            $theme = theme_config::load($themename);
-            redirect($theme->pix_url('u/'.$filename, 'moodle'));
-        }
-        send_stored_file($file, 60*60*24); // enable long caching, there are many images on each page
-
-    } else if ($filearea === 'private' and $context->contextlevel == CONTEXT_USER) {
-        require_login();
-
-        if (isguestuser()) {
-            send_file_not_found();
-        }
-
-        if ($USER->id !== $context->instanceid) {
-            send_file_not_found();
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 0, 0, true); // must force download - security!
-
-    } else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_USER) {
-
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-        $userid = $context->instanceid;
-
-        if ($USER->id == $userid) {
-            // always can access own
-
-        } else if (!empty($CFG->forceloginforprofiles)) {
-            require_login();
-
-            if (isguestuser()) {
-                send_file_not_found();
-            }
-
-            // we allow access to site profile of all course contacts (usually teachers)
-            if (!has_coursecontact_role($userid) && !has_capability('moodle/user:viewdetails', $context)) {
-                send_file_not_found();
-            }
-
-            $canview = false;
-            if (has_capability('moodle/user:viewdetails', $context)) {
-                $canview = true;
-            } else {
-                $courses = enrol_get_my_courses();
-            }
-
-            while (!$canview && count($courses) > 0) {
-                $course = array_shift($courses);
-                if (has_capability('moodle/user:viewdetails', get_context_instance(CONTEXT_COURSE, $course->id))) {
-                    $canview = true;
-                }
-            }
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, $component, $filearea, 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 0, 0, true); // must force download - security!
-
-    } else if ($filearea === 'profile' and $context->contextlevel == CONTEXT_COURSE) {
-        $userid = (int)array_shift($args);
-        $usercontext = get_context_instance(CONTEXT_USER, $userid);
-
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-        if (!empty($CFG->forceloginforprofiles)) {
-            require_login();
-            if (isguestuser()) {
-                print_error('noguest');
-            }
-
-            //TODO: review this logic of user profile access prevention
-            if (!has_coursecontact_role($userid) and !has_capability('moodle/user:viewdetails', $usercontext)) {
-                print_error('usernotavailable');
-            }
-            if (!has_capability('moodle/user:viewdetails', $context) && !has_capability('moodle/user:viewdetails', $usercontext)) {
-                print_error('cannotviewprofile');
-            }
-            if (!is_enrolled($context, $userid)) {
-                print_error('notenrolledprofile');
-            }
-            if (groups_get_course_groupmode($course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
-                print_error('groupnotamember');
-            }
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($usercontext->id, 'user', 'profile', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 0, 0, true); // must force download - security!
-
-    } else if ($filearea === 'backup' and $context->contextlevel == CONTEXT_USER) {
-        require_login();
-
-        if (isguestuser()) {
-            send_file_not_found();
-        }
-        $userid = $context->instanceid;
-
-        if ($USER->id != $userid) {
-            send_file_not_found();
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'user', 'backup', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 0, 0, true); // must force download - security!
-
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'coursecat') {
-    if ($context->contextlevel != CONTEXT_COURSECAT) {
-        send_file_not_found();
-    }
-
-    if ($filearea === 'description') {
-        if ($CFG->forcelogin) {
-            // no login necessary - unless login forced everywhere
-            require_login();
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'coursecat', 'description', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'course') {
-    if ($context->contextlevel != CONTEXT_COURSE) {
-        send_file_not_found();
-    }
-
-    if ($filearea === 'summary') {
-        if ($CFG->forcelogin) {
-            require_login();
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'course', 'summary', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'section') {
-        if ($CFG->forcelogin) {
-            require_login($course);
-        } else if ($course->id != SITEID) {
-            require_login($course);
-        }
-
-        $sectionid = (int)array_shift($args);
-
-        if (!$section = $DB->get_record('course_sections', array('id'=>$sectionid, 'course'=>$course->id))) {
-            send_file_not_found();
-        }
-
-        if ($course->numsections < $section->section) {
-            if (!has_capability('moodle/course:update', $context)) {
-                // block access to unavailable sections if can not edit course
-                send_file_not_found();
-            }
-        }
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'course', 'section', $sectionid, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else {
-        send_file_not_found();
-    }
-
-} else if ($component === 'group') {
-    if ($context->contextlevel != CONTEXT_COURSE) {
-        send_file_not_found();
-    }
-
-    require_course_login($course, true, null, false);
-
-    $groupid = (int)array_shift($args);
-
-    $group = $DB->get_record('groups', array('id'=>$groupid, 'courseid'=>$course->id), '*', MUST_EXIST);
-    if (($course->groupmodeforce and $course->groupmode == SEPARATEGROUPS) and !has_capability('moodle/site:accessallgroups', $context) and !groups_is_member($group->id, $USER->id)) {
-        // do not allow access to separate group info if not member or teacher
-        send_file_not_found();
-    }
-
-    if ($filearea === 'description') {
-
-        require_login($course);
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'group', 'description', $group->id, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'icon') {
-        $filename = array_pop($args);
-
-        if ($filename !== 'f1' and $filename !== 'f2') {
-            send_file_not_found();
-        }
-        if (!$file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename.'.png')) {
-            if (!$file = $fs->get_file($context->id, 'group', 'icon', $group->id, '/', $filename.'.jpg')) {
-                send_file_not_found();
-            }
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60);
-
-    } else {
-        send_file_not_found();
-    }
-
-} else if ($component === 'grouping') {
-    if ($context->contextlevel != CONTEXT_COURSE) {
-        send_file_not_found();
-    }
-
-    require_login($course);
-
-    $groupingid = (int)array_shift($args);
-
-    // note: everybody has access to grouping desc images for now
-    if ($filearea === 'description') {
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'grouping', 'description', $groupingid, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'backup') {
-    if ($filearea === 'course' and $context->contextlevel == CONTEXT_COURSE) {
-        require_login($course);
-        require_capability('moodle/backup:downloadfile', $context);
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'backup', 'course', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 0, 0, $forcedownload);
-
-    } else if ($filearea === 'section' and $context->contextlevel == CONTEXT_COURSE) {
-        require_login($course);
-        require_capability('moodle/backup:downloadfile', $context);
-
-        $sectionid = (int)array_shift($args);
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'backup', 'section', $sectionid, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close();
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'activity' and $context->contextlevel == CONTEXT_MODULE) {
-        require_login($course, false, $cm);
-        require_capability('moodle/backup:downloadfile', $context);
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'backup', 'activity', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close();
-        send_stored_file($file, 60*60, 0, $forcedownload);
-
-    } else if ($filearea === 'automated' and $context->contextlevel == CONTEXT_COURSE) {
-        // Backup files that were generated by the automated backup systems.
-
-        require_login($course);
-        require_capability('moodle/site:config', $context);
-
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'backup', 'automated', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 0, 0, $forcedownload);
-
-    } else {
-        send_file_not_found();
-    }
-
-// ========================================================================================================================
-} else if ($component === 'question') {
-    require_once($CFG->libdir . '/questionlib.php');
-    question_pluginfile($course, $context, 'question', $filearea, $args, $forcedownload);
-    send_file_not_found();
-
-// ========================================================================================================================
-} else if ($component === 'grading') {
-    if ($filearea === 'description') {
-        // files embedded into the form definition description
-
-        if ($context->contextlevel == CONTEXT_SYSTEM) {
-            require_login();
-
-        } else if ($context->contextlevel >= CONTEXT_COURSE) {
-            require_login($course, false, $cm);
-
-        } else {
-            send_file_not_found();
-        }
-
-        $formid = (int)array_shift($args);
-
-        $sql = "SELECT ga.id
-                  FROM {grading_areas} ga
-                  JOIN {grading_definitions} gd ON (gd.areaid = ga.id)
-                 WHERE gd.id = ? AND ga.contextid = ?";
-        $areaid = $DB->get_field_sql($sql, array($formid, $context->id), IGNORE_MISSING);
-
-        if (!$areaid) {
-            send_file_not_found();
-        }
-
-        $fullpath = "/$context->id/$component/$filearea/$formid/".implode('/', $args);
-
-        if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        session_get_instance()->write_close(); // unlock session during fileserving
-        send_stored_file($file, 60*60, 0, $forcedownload);
-    }
-
-// ========================================================================================================================
-} else if (strpos($component, 'mod_') === 0) {
-    $modname = substr($component, 4);
-    if (!file_exists("$CFG->dirroot/mod/$modname/lib.php")) {
-        send_file_not_found();
-    }
-    require_once("$CFG->dirroot/mod/$modname/lib.php");
-
-    if ($context->contextlevel == CONTEXT_MODULE) {
-        if ($cm->modname !== $modname) {
-            // somebody tries to gain illegal access, cm type must match the component!
-            send_file_not_found();
-        }
-    }
-
-    if ($filearea === 'intro') {
-        if (!plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)) {
-            send_file_not_found();
-        }
-        require_course_login($course, true, $cm);
-
-        // all users may access it
-        $filename = array_pop($args);
-        $filepath = $args ? '/'.implode('/', $args).'/' : '/';
-        if (!$file = $fs->get_file($context->id, 'mod_'.$modname, 'intro', 0, $filepath, $filename) or $file->is_directory()) {
-            send_file_not_found();
-        }
-
-        $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
-
-        // finally send the file
-        send_stored_file($file, $lifetime, 0);
-    }
-
-    $filefunction = $component.'_pluginfile';
-    $filefunctionold = $modname.'_pluginfile';
-    if (function_exists($filefunction)) {
-        // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
-        $filefunction($course, $cm, $context, $filearea, $args, $forcedownload);
-    } else if (function_exists($filefunctionold)) {
-        // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
-        $filefunctionold($course, $cm, $context, $filearea, $args, $forcedownload);
-    }
-
-    send_file_not_found();
-
-// ========================================================================================================================
-} else if (strpos($component, 'block_') === 0) {
-    $blockname = substr($component, 6);
-    // note: no more class methods in blocks please, that is ....
-    if (!file_exists("$CFG->dirroot/blocks/$blockname/lib.php")) {
-        send_file_not_found();
-    }
-    require_once("$CFG->dirroot/blocks/$blockname/lib.php");
-
-    if ($context->contextlevel == CONTEXT_BLOCK) {
-        $birecord = $DB->get_record('block_instances', array('id'=>$context->instanceid), '*',MUST_EXIST);
-        if ($birecord->blockname !== $blockname) {
-            // somebody tries to gain illegal access, cm type must match the component!
-            send_file_not_found();
-        }
-    } else {
-        $birecord = null;
-    }
-
-    $filefunction = $component.'_pluginfile';
-    if (function_exists($filefunction)) {
-        // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
-        $filefunction($course, $birecord, $context, $filearea, $args, $forcedownload);
-    }
-
-    send_file_not_found();
-
-} else if (strpos($component, '_') === false) {
-    // all core subsystems have to be specified above, no more guessing here!
-    send_file_not_found();
-
-} else {
-    // try to serve general plugin file in arbitrary context
-    $dir = get_component_directory($component);
-    if (!file_exists("$dir/lib.php")) {
-        send_file_not_found();
-    }
-    include_once("$dir/lib.php");
-
-    $filefunction = $component.'_pluginfile';
-    if (function_exists($filefunction)) {
-        // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
-        $filefunction($course, $cm, $context, $filearea, $args, $forcedownload);
-    }
-
-    send_file_not_found();
-}
+file_pluginfile($relativepath, $forcedownload);
index eb6f4d8..d49de62 100644 (file)
@@ -243,7 +243,7 @@ class portfolio_plugin_boxnet extends portfolio_plugin_push_base {
     }
 
     public function supported_formats() {
-        return array(PORTFOLIO_FORMAT_FILE); // don't support rich html, it breaks links
+        return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML);
     }
 
     /*
index 081444d..2633deb 100644 (file)
@@ -184,9 +184,10 @@ class qformat_xml extends qformat_default {
             $data = new stdClass();
             $data->content = $filedata;
             $data->encoding = 'base64';
-            $data->name = $filename;
+            // Question file areas don't support subdirs, so convert path to filename if necessary.
+            $data->name = clean_param(str_replace('/', '_', $filename), PARAM_FILE);
             $qo->questiontextfiles[] = $data;
-            $qo->questiontext .= ' <img src="@@PLUGINFILE@@/' . $filename . '" />';
+            $qo->questiontext .= ' <img src="@@PLUGINFILE@@/' . $data->name . '" />';
         }
 
         // restore files in generalfeedback
index fc3564a..3d07083 100644 (file)
@@ -267,10 +267,7 @@ class question_dataset_dependent_items_form extends moodleform {
         $mform->closeHeaderBefore('addgrp1');
         //----------------------------------------------------------------------
         $j = $this->noofitems * count($this->datasetdefs);
-        $k = 1;
-        if ("" != optional_param('selectshow', '', PARAM_INT)) {
-            $k = optional_param('selectshow', '', PARAM_INT);
-        }
+        $k = optional_param('selectshow', 1, PARAM_INT);
         for ($i = $this->noofitems; $i >= 1; $i--) {
             if ($k > 0) {
                 $mform->addElement('header', '', "<b>" .
@@ -361,8 +358,8 @@ class question_dataset_dependent_items_form extends moodleform {
         if (isset($question->options)) {
             $answers = $question->options->answers;
             if (count($answers)) {
-                if (optional_param('updateanswers', '', PARAM_RAW) != '' ||
-                        optional_param('updatedatasets', '', PARAM_RAW) != '') {
+                if (optional_param('updateanswers', false, PARAM_BOOL) ||
+                        optional_param('updatedatasets', false, PARAM_BOOL)) {
                     foreach ($answers as $key => $answer) {
                         $fromform->tolerance[$key]= $this->_form->getElementValue(
                                 'tolerance['.$key.']');
@@ -434,8 +431,8 @@ class question_dataset_dependent_items_form extends moodleform {
         if ($this->qtypeobj->supports_dataset_item_generation()) {
             $itemnumber = $this->noofitems+1;
             foreach ($this->datasetdefs as $defid => $datasetdef) {
-                if (optional_param('updatedatasets', '', PARAM_RAW) == '' &&
-                        optional_param('updateanswers', '', PARAM_RAW)== '') {
+                if (!optional_param('updatedatasets', false, PARAM_BOOL) &&
+                        !optional_param('updateanswers', false, PARAM_BOOL)) {
                     $formdata["number[$j]"] = $this->qtypeobj->generate_dataset_item(
                             $datasetdef->options);
                 } else {
@@ -450,11 +447,11 @@ class question_dataset_dependent_items_form extends moodleform {
         }
 
         //existing records override generated data depending on radio element
-        $j = $this->noofitems * count($this->datasetdefs)+1;
-        if (!$this->regenerate && (optional_param('updatedatasets', '', PARAM_RAW) == '' &&
-                optional_param('updateanswers', '', PARAM_RAW)== '')) {
+        $j = $this->noofitems * count($this->datasetdefs) + 1;
+        if (!$this->regenerate && !optional_param('updatedatasets', false, PARAM_BOOL) &&
+                !optional_param('updateanswers', false, PARAM_BOOL)) {
             $idx = 1;
-            $itemnumber = $this->noofitems+1;
+            $itemnumber = $this->noofitems + 1;
             foreach ($this->datasetdefs as $defid => $datasetdef) {
                 if (isset($datasetdef->items[$itemnumber])) {
                     $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
@@ -468,7 +465,7 @@ class question_dataset_dependent_items_form extends moodleform {
 
         $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
                 $question->questiontext, $answers, $data, ($this->noofitems + 1));
-        if (isset($comment->outsidelimit)&&$comment->outsidelimit) {
+        if (isset($comment->outsidelimit) && $comment->outsidelimit) {
             $this->outsidelimit=$comment->outsidelimit;
         }
         $key1 = 1;
index 9fb391c..76dc6cd 100644 (file)
@@ -52,11 +52,7 @@ class qtype_calculated_edit_form extends qtype_numerical_edit_form {
             $formeditable = true) {
         global $CFG, $DB;
         $this->question = $question;
-        if ('1' == optional_param('reload', '', PARAM_INT)) {
-            $this->reload = true;
-        } else {
-            $this->reload = false;
-        }
+        $this->reload = optional_param('reload', false, PARAM_BOOL);
 
         if (!$this->reload) { // use database data as this is first pass
             if (isset($this->question->id)) {
index 4b6a132..16a8785 100644 (file)
@@ -436,7 +436,7 @@ class qtype_calculated extends question_type {
                 break;
             case 'datasetitems':
                 require("$CFG->dirroot/question/type/calculated/datasetitems_form.php");
-                $regenerate = optional_param('forceregeneration', 0, PARAM_BOOL);
+                $regenerate = optional_param('forceregeneration', false, PARAM_BOOL);
                 $mform = new question_dataset_dependent_items_form(
                         "$submiturl?wizardnow=datasetitems", $question, $regenerate);
                 break;
index eec57e3..ff2b986 100644 (file)
@@ -48,11 +48,7 @@ class qtype_calculatedmulti_edit_form extends question_edit_form {
             $contexts, $formeditable = true) {
         $this->question = $question;
         $this->qtypeobj = question_bank::get_qtype('calculatedmulti');
-        if (1 == optional_param('reload', '', PARAM_INT)) {
-            $this->reload = true;
-        } else {
-            $this->reload = false;
-        }
+        $this->reload = optional_param('reload', false, PARAM_BOOL);
         if (!$this->reload) {
             // use database data as this is first pass
             if (isset($this->question->id)) {
@@ -158,11 +154,11 @@ class qtype_calculatedmulti_edit_form extends question_edit_form {
         $mform->setConstants(array('nounits'=>$nounits));
         for ($i = 0; $i < $nounits; $i++) {
             $mform->addElement('hidden', 'unit'."[$i]",
-                    optional_param('unit'."[$i]", '', PARAM_NOTAGS));
+                    optional_param("unit[$i]", '', PARAM_NOTAGS));
             $mform->setType('unit'."[$i]", PARAM_NOTAGS);
             $mform->addElement('hidden', 'multiplier'."[$i]",
-                    optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
-            $mform->setType('multiplier'."[$i]", PARAM_NUMBER);
+                    optional_param("multiplier[$i]", '', PARAM_NUMBER));
+            $mform->setType("multiplier[$i]", PARAM_NUMBER);
         }
 
         $this->add_combined_feedback_fields(true);
index 5ba6cd1..d9dae12 100644 (file)
@@ -80,11 +80,7 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
         // which is not what we want so this should be removed from here
         // get priority to paramdatasets
 
-        if ("1" == optional_param('reload', '', PARAM_INT)) {
-            $this->reload = true;
-        } else {
-            $this->reload = false;
-        }
+        $this->reload = optional_param('reload', false, PARAM_BOOL);
         if (!$this->reload) { // use database data as this is first pass
             // question->id == 0 so no stored datasets
             if (!empty($question->id)) {
@@ -145,16 +141,16 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
             // should not test on adding a new answer
             // should test if there are already olddatasets or if the 'analyzequestion'
             // submit button has been clicked
-            if ('' != optional_param('datasetdef', '', PARAM_RAW) ||
-                    '' != optional_param('analyzequestion', '', PARAM_RAW)) {
+            if (optional_param_array('datasetdef', false, PARAM_BOOL) ||
+                    optional_param('analyzequestion', false, PARAM_BOOL)) {
 
-                if ($dummyform->answer = optional_param('answer', '', PARAM_NOTAGS)) {
+                if ($dummyform->answer = optional_param_array('answer', '', PARAM_NOTAGS)) {
                     // there is always at least one answer...
-                    $fraction = optional_param('fraction', '', PARAM_NUMBER);
-                    $tolerance = optional_param('tolerance', '', PARAM_NUMBER);
-                    $tolerancetype = optional_param('tolerancetype', '', PARAM_NUMBER);
-                    $correctanswerlength = optional_param('correctanswerlength', '', PARAM_INT);
-                    $correctanswerformat = optional_param('correctanswerformat', '', PARAM_INT);
+                    $fraction = optional_param_array('fraction', '', PARAM_NUMBER);
+                    $tolerance = optional_param_array('tolerance', '', PARAM_NUMBER);
+                    $tolerancetype = optional_param_array('tolerancetype', '', PARAM_NUMBER);
+                    $correctanswerlength = optional_param_array('correctanswerlength', '', PARAM_INT);
+                    $correctanswerformat = optional_param_array('correctanswerformat', '', PARAM_INT);
 
                     foreach ($dummyform->answer as $key => $answer) {
                         if (trim($answer) != '') {  // just look for non-empty
@@ -172,11 +168,11 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
                 }
                 $this->datasetdefs = array();
                 // rebuild datasetdefs from old values
-                if ($olddef = optional_param('datasetdef', '', PARAM_RAW)) {
-                    $calcmin = optional_param('calcmin', '', PARAM_NUMBER);
-                    $calclength = optional_param('calclength', '', PARAM_INT);
-                    $calcmax = optional_param('calcmax', '', PARAM_NUMBER);
-                    $oldoptions  = optional_param('defoptions', '', PARAM_RAW);
+                if ($olddef = optional_param_array('datasetdef', '', PARAM_RAW)) {
+                    $calcmin = optional_param_array('calcmin', '', PARAM_NUMBER);
+                    $calclength = optional_param_array('calclength', '', PARAM_INT);
+                    $calcmax = optional_param_array('calcmax', '', PARAM_NUMBER);
+                    $oldoptions  = optional_param_array('defoptions', '', PARAM_RAW);
                     $newdatasetvalues = false;
                     $sizeofolddef = count($olddef);
                     for ($key = 1; $key <= $sizeofolddef; $key++) {
@@ -238,7 +234,7 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
             }
         }
         $maxnumber = -1;
-        if ("" != optional_param('addbutton', '', PARAM_TEXT)) {
+        if (optional_param('addbutton', false, PARAM_BOOL)) {
             $maxnumber = optional_param('selectadd', '', PARAM_INT); //FIXME: sloppy coding
             foreach ($this->datasetdefs as $defid => $datasetdef) {
                 $datasetdef->itemcount = $maxnumber;
@@ -255,12 +251,12 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
             $this->maxnumber = $maxnumber;
         } else {
             // Handle reload dataset items
-            if ("" != optional_param('definition', '', PARAM_NOTAGS) &&
+            if (optional_param_array('definition', '', PARAM_NOTAGS) &&
                     !($datasettoremove ||$newdataset ||$newdatasetvalues)) {
                 $i = 1;
-                $fromformdefinition = optional_param('definition', '', PARAM_NOTAGS);
-                $fromformnumber = optional_param('number', '', PARAM_INT);
-                $fromformitemid = optional_param('itemid', '', PARAM_INT);
+                $fromformdefinition = optional_param_array('definition', '', PARAM_NOTAGS);
+                $fromformnumber = optional_param_array('number', '', PARAM_INT);
+                $fromformitemid = optional_param_array('itemid', '', PARAM_INT);
                 ksort($fromformdefinition);
 
                 foreach ($fromformdefinition as $key => $defid) {
@@ -320,7 +316,7 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
                 get_string('findwildcards', 'qtype_calculatedsimple'));
         $mform->registerNoSubmitButton('analyzequestion');
         $mform->closeHeaderBefore('analyzequestion');
-        if ("" != optional_param('analyzequestion', '', PARAM_RAW)) {
+        if (optional_param('analyzequestion', false, PARAM_BOOL)) {
 
             $this->wizarddisplay = true;
 
@@ -499,10 +495,7 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
 
                 //--------------------------------------------------------------
                 $j = $this->noofitems * count($this->datasetdefs);
-                $k = 1;
-                if ("" != optional_param('selectshow', '', PARAM_INT)) {
-                    $k = optional_param('selectshow', '', PARAM_INT);
-                }
+                $k = optional_param('selectshow', 1, PARAM_INT);
 
                 for ($i = $this->noofitems; $i >= 1; $i--) {
                     foreach ($this->datasetdefs as $defkey => $datasetdef) {
index d779aa7..f2cc2bf 100644 (file)
@@ -53,11 +53,7 @@ class qtype_multianswer_edit_form extends question_edit_form {
     public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
         global $SESSION, $CFG, $DB;
         $this->regenerate = true;
-        if ("1" == optional_param('reload', '', PARAM_INT)) {
-            $this->reload = true;
-        } else {
-            $this->reload = false;
-        }
+        $this->reload = optional_param('reload', false, PARAM_BOOL);
 
         $this->used_in_quiz = false;
 
@@ -85,7 +81,7 @@ class qtype_multianswer_edit_form extends question_edit_form {
 
         // Remove meaningless defaultmark field.
         $mform->removeElement('defaultmark');
-        $this->confirm = optional_param('confirm', '0', PARAM_RAW);
+        $this->confirm = optional_param('confirm', false, PARAM_BOOL);
 
         // Make questiontext a required field for this question type.
         $mform->addRule('questiontext', null, 'required', null, 'client');
@@ -145,11 +141,10 @@ class qtype_multianswer_edit_form extends question_edit_form {
         if ($this->reload) {
             for ($sub = 1; $sub <= $countsubquestions; $sub++) {
 
-                $this->editas[$sub] = 'unknown type';
                 if (isset($this->questiondisplay->options->questions[$sub]->qtype)) {
                     $this->editas[$sub] = $this->questiondisplay->options->questions[$sub]->qtype;
-                } else if (optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW) != '') {
-                    $this->editas[$sub] = optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW);
+                } else {
+                    $this->editas[$sub] = optional_param('sub_'.$sub.'_qtype', 'unknown type', PARAM_PLUGIN);
                 }
 
                 $storemess = '';
@@ -167,43 +162,43 @@ class qtype_multianswer_edit_form extends question_edit_form {
                        '{#'.$sub.'}').'&nbsp;'.question_bank::get_qtype_name(
                         $this->questiondisplay->options->questions[$sub]->qtype).$storemess);
 
-                $mform->addElement('static', 'sub_'.$sub."_".'questiontext',
+                $mform->addElement('static', 'sub_'.$sub.'_questiontext',
                         get_string('questiondefinition', 'qtype_multianswer'));
 
                 if (isset ($this->questiondisplay->options->questions[$sub]->questiontext)) {
-                    $mform->setDefault('sub_'.$sub."_".'questiontext',
+                    $mform->setDefault('sub_'.$sub.'_questiontext',
                             $this->questiondisplay->options->questions[$sub]->questiontext['text']);
                 }
 
-                $mform->addElement('static', 'sub_'.$sub."_".'defaultmark',
+                $mform->addElement('static', 'sub_'.$sub.'_defaultmark',
                         get_string('defaultmark', 'question'));
-                $mform->setDefault('sub_'.$sub."_".'defaultmark',
+                $mform->setDefault('sub_'.$sub.'_defaultmark',
                         $this->questiondisplay->options->questions[$sub]->defaultmark);
 
                 if ($this->questiondisplay->options->questions[$sub]->qtype == 'shortanswer') {
-                    $mform->addElement('static', 'sub_'.$sub."_".'usecase',
+                    $mform->addElement('static', 'sub_'.$sub.'_usecase',
                             get_string('casesensitive', 'qtype_shortanswer'));
                 }
 
                 if ($this->questiondisplay->options->questions[$sub]->qtype == 'multichoice') {
-                    $mform->addElement('static', 'sub_'.$sub."_".'layout',
+                    $mform->addElement('static', 'sub_'.$sub.'_layout',
                             get_string('layout', 'qtype_multianswer'));
                 }
 
                 foreach ($this->questiondisplay->options->questions[$sub]->answer as $key => $ans) {
-                    $mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']',
+                    $mform->addElement('static', 'sub_'.$sub.'_answer['.$key.']',
                             get_string('answer', 'question'));
 
                     if ($this->questiondisplay->options->questions[$sub]->qtype == 'numerical' &&
                             $key == 0) {
-                        $mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']',
+                        $mform->addElement('static', 'sub_'.$sub.'_tolerance['.$key.']',
                                 get_string('acceptederror', 'qtype_numerical'));
                     }
 
-                    $mform->addElement('static', 'sub_'.$sub."_".'fraction['.$key.']',
+                    $mform->addElement('static', 'sub_'.$sub.'_fraction['.$key.']',
                             get_string('grade'));
 
-                    $mform->addElement('static', 'sub_'.$sub."_".'feedback['.$key.']',
+                    $mform->addElement('static', 'sub_'.$sub.'_feedback['.$key.']',
                             get_string('feedback', 'question'));
                 }
             }
@@ -490,7 +485,7 @@ class qtype_multianswer_edit_form extends question_edit_form {
 
         if (($this->negative_diff > 0 || $this->used_in_quiz &&
                 ($this->negative_diff > 0 || $this->negative_diff < 0 ||
-                        $this->qtype_change))&& $this->confirm == 0) {
+                        $this->qtype_change)) && !$this->confirm) {
             $errors['confirm'] =
                     get_string('confirmsave', 'qtype_multianswer', $this->negative_diff);
         }
index 2b0a380..e639d59 100644 (file)
@@ -66,7 +66,7 @@ class repository_dropbox extends repository {
             'oauth_consumer_key'=>$this->dropbox_key,
             'oauth_consumer_secret'=>$this->dropbox_secret,
             'oauth_callback' => $this->callback->out(false),
-            'api_root' => 'http://www.dropbox.com/0/oauth',
+            'api_root' => 'https://www.dropbox.com/1/oauth',
         );
 
         $this->dropbox = new dropbox($args);
@@ -96,7 +96,7 @@ class repository_dropbox extends repository {
             $ret['login'] = array($popup_btn);
             return $ret;
         } else {
-            echo '<a target="_blank" href="'.$this->flickr->auth().'">'.get_string('login', 'repository').'</a>';
+            echo '<a target="_blank" href="'.$url.'">'.get_string('login', 'repository').'</a>';
         }
     }
 
index 21adb82..c5edf11 100644 (file)
@@ -35,9 +35,9 @@ class dropbox extends oauth_helper {
     /** dropbox access type, can be dropbox or sandbox */
     private $mode = 'dropbox';
     /** dropbox api url*/
-    private $dropbox_api = 'http://api.dropbox.com/0';
+    private $dropbox_api = 'https://api.dropbox.com/1';
     /** dropbox content api url*/
-    private $dropbox_content_api = 'http://api-content.dropbox.com/0';
+    private $dropbox_content_api = 'https://api-content.dropbox.com/1';
 
     function __construct($args) {
         parent::__construct($args);
@@ -52,15 +52,6 @@ class dropbox extends oauth_helper {
         return $data;
     }
 
-    /**
-     * Get user account info
-     */
-    public function get_account_info($token, $secret) {
-        $url = $this->dropbox_api.'/account/info';
-        $content = $this->get($url, array(), $token, $secret);
-        return $content;
-    }
-
     /**
      * Download a file
      */
index 74c788e..7b7cd46 100644 (file)
@@ -324,7 +324,7 @@ function tag_print_user_box($user, $return=false) {
     $usercontext = get_context_instance(CONTEXT_USER, $user->id);
     $profilelink = '';
 
-    if ( has_capability('moodle/user:viewdetails', $usercontext) || has_coursecontact_role($user->id) ) {
+    if ($usercontext and (has_capability('moodle/user:viewdetails', $usercontext) || has_coursecontact_role($user->id))) {
         $profilelink = $CFG->wwwroot .'/user/view.php?id='. $user->id;
     }
 
index 47ef877..ca351e3 100644 (file)
@@ -130,4 +130,6 @@ $THEME->layouts = array(
 
 $THEME->enable_dock = true;
 
-$THEME->rendererfactory = 'theme_overridden_renderer_factory';
\ No newline at end of file
+$THEME->rendererfactory = 'theme_overridden_renderer_factory';
+
+$THEME->csspostprocess = 'afterburner_process_css';
\ No newline at end of file
index 48d12c4..fb5736e 100644 (file)
  * @copyright 2011
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-
+$string['configtitle'] = 'Afterburner Custom Settings';
 $string['pluginname'] = 'Afterburner';
 $string['region-side-post'] = 'Right';
 $string['region-side-pre'] = 'Left';
+$string['logo'] = 'Logo';
+$string['logodesc'] = 'Please add the URL to your new logo only if you want to replace the default logo for this theme.<br />For your information, the default logo is a JPG image 320px (wide) by 75px (high)';
+$string['footnote'] = 'Footnote';
+$string['footnotedesc'] = 'Whatever you add to this textarea will be displayed in the footer of every page.';
+$string['customcss'] = 'Custom CSS';
+$string['customcssdesc'] = 'Whatever CSS rules you add to this textarea will be reflected in every page, making for easier customization of this theme.';
 $string['choosereadme'] = '
 <div class="clearfix">
  <div class="theme_screenshot">
index 8c29b7c..a6b39d0 100644 (file)
@@ -13,6 +13,8 @@ $showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-
 $custommenu = $OUTPUT->custom_menu();
 $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
+$hasfootnote = (!empty($PAGE->theme->settings->footnote));
+
 $bodyclasses = array();
 if ($showsidepre && !$showsidepost) {
     $bodyclasses[] = 'side-pre-only';
@@ -108,6 +110,11 @@ echo $OUTPUT->doctype() ?>
     <div id="page-footer" class="clearfix">
 
         <div class="footer-left">
+
+            <?php if ($hasfootnote) { ?>
+                    <div id="footnote"><?php echo $PAGE->theme->settings->footnote;?></div>
+            <?php } ?>
+
             <a href="http://moodle.org" title="Moodle">
                 <img src="<?php echo $OUTPUT->pix_url('footer/moodle-logo','theme')?>" alt="Moodle logo" />
             </a>
diff --git a/theme/afterburner/lib.php b/theme/afterburner/lib.php
new file mode 100644 (file)
index 0000000..11a4ec4
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+function afterburner_process_css($css, $theme) {
+
+    // Set the background image for the logo
+    if (!empty($theme->settings->logo)) {
+        $logo = $theme->settings->logo;
+    } else {
+        $logo = null;
+    }
+    $css = afterburner_set_logo($css, $logo);
+
+    // Set custom CSS
+    if (!empty($theme->settings->customcss)) {
+        $customcss = $theme->settings->customcss;
+    } else {
+        $customcss = null;
+    }
+    $css = afterburner_set_customcss($css, $customcss);
+
+    return $css;
+}
+
+function afterburner_set_logo($css, $logo) {
+    global $OUTPUT;
+    $tag = '[[setting:logo]]';
+    $replacement = $logo;
+    if (is_null($replacement)) {
+        $replacement = $OUTPUT->pix_url('images/logo','theme');
+    }
+
+    $css = str_replace($tag, $replacement, $css);
+
+    return $css;
+}
+
+function afterburner_set_customcss($css, $customcss) {
+    $tag = '[[setting:customcss]]';
+    $replacement = $customcss;
+    if (is_null($replacement)) {
+        $replacement = '';
+    }
+
+    $css = str_replace($tag, $replacement, $css);
+
+    return $css;
+}
\ No newline at end of file
diff --git a/theme/afterburner/pix/images/logo.jpg b/theme/afterburner/pix/images/logo.jpg
new file mode 100644 (file)
index 0000000..fcd2fe0
Binary files /dev/null and b/theme/afterburner/pix/images/logo.jpg differ
diff --git a/theme/afterburner/settings.php b/theme/afterburner/settings.php
new file mode 100644 (file)
index 0000000..c68a599
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+
+    // Logo file setting
+    $name = 'theme_afterburner/logo';
+    $title = get_string('logo','theme_afterburner');
+    $description = get_string('logodesc', 'theme_afterburner');
+    $default = '';
+    $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
+    $settings->add($setting);
+
+    // Foot note setting
+    $name = 'theme_afterburner/footnote';
+    $title = get_string('footnote','theme_afterburner');
+    $description = get_string('footnotedesc', 'theme_afterburner');
+    $default = '';
+    $setting = new admin_setting_confightmleditor($name, $title, $description, $default);
+    $settings->add($setting);
+
+    // Custom CSS file
+    $name = 'theme_afterburner/customcss';
+    $title = get_string('customcss','theme_afterburner');
+    $description = get_string('customcssdesc', 'theme_afterburner');
+    $default = '';
+    $setting = new admin_setting_configtextarea($name, $title, $description, $default);
+    $settings->add($setting);
+
+}
\ No newline at end of file
index 6c1b5bd..d6d4855 100644 (file)
@@ -19,8 +19,8 @@ a:hover, a:active {
     text-decoration: none;
 }
 hr {
-    border-bottom:1px dotted gray;
-    border-top:0px;
+    border-bottom: 1px dotted #808080;
+    border-top: 0px;
 }
 h2.headingblock {
     border-bottom: 1px solid #ddd;
@@ -46,11 +46,11 @@ Header and Logo
     background: #fff;
 }
 #logo {
-    background: url([[pix:theme|images/light3]]) no-repeat 0 -272px;
-    width: 288px;
-    height: 58px;
+    background: url([[setting:logo]]) no-repeat 0 0;
+    width: 320px;
+    height: 75px;
     display: block;
-    margin: 20px 15px;
+    margin: 15px 10px 10px;
     float: left;
 }
 .headermenu,
@@ -72,13 +72,13 @@ Page Footer
 #page-footer {
     background: #fff url([[pix:theme|core/h2grad]]) repeat-x left top;
     height: auto;
-    clear:both;
-    float:left;
-    width:98%;
+    clear: both;
+    float: left;
+    width: 98%;
     margin: 0;
     padding: 1%;
     color: #4b4b4b;
-    border-top:1px solid #fff;
+    border-top: 1px solid #fff;
     line-height: 2em;
     font-size: 1em;
 }
@@ -97,6 +97,12 @@ Page Footer
     text-align: left;
     color: #999;
 }
+#page-footer .footer-left p {
+    margin: 0;
+    padding: 0;
+    font-size: 100%;
+    line-height: 1;
+}
 #page-footer .footer-right {
     float: right;
     text-align: right;
@@ -433,4 +439,8 @@ tab styles for ie6 & ie7
 }
 .yui-skin-sam .yui-panel-container {
     z-index: 999999!important;
-}
\ No newline at end of file
+}
+
+/* Custom CSS Settings
+-------------------------*/
+[[setting:customcss]]
\ No newline at end of file
index a83a595..8b6746d 100644 (file)
@@ -7,7 +7,7 @@
 
 $THEME->name = 'anomaly';
 
-$THEME->sheets = array('base', 'general', 'browser');
+$THEME->sheets = array('base', 'general', 'browser','dock');
 /// This variable is an array containing the names of all the
 /// stylesheet files you want included in this theme, and in what order
 ////////////////////////////////////////////////////////////////////////////////
index 0540994..253541e 100644 (file)
@@ -21,6 +21,9 @@ if ($showsidepre && !$showsidepost) {
 if ($hascustommenu) {
     $bodyclasses[] = 'has_custom_menu';
 }
+if ($hasnavbar) {
+    $bodyclasses[] = 'hasnavbar';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -106,6 +109,7 @@ echo $OUTPUT->doctype() ?>
         <div class="rounded-corner bottom-right"></div>
     </div>
     <?php } ?>
+  <div class="clearfix"></div>
 </div>
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
index cde10e4..91b9049 100644 (file)
@@ -15,6 +15,9 @@ if (!$showsidepre) {
 if ($hascustommenu) {
     $bodyclasses[] = 'has_custom_menu';
 }
+if ($hasnavbar) {
+    $bodyclasses[] = 'hasnavbar';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -85,6 +88,7 @@ echo $OUTPUT->doctype() ?>
         <div class="rounded-corner bottom-right"></div>
     </div>
     <?php } ?>
+  <div class="clearfix"></div>
 </div>
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
index 7d60fac..019f657 100644 (file)
@@ -2,11 +2,6 @@
  * Core
  */
 
-body,
-body.has_dock {
-    margin: 25px 3%;
-}
-
 #page, div, p, li, input, option, textarea {
     font-size: 10pt;
     line-height: 1.5em;
@@ -16,6 +11,13 @@ body.has_dock {
     font-family: Georgia,Times,"Times New Roman",serif;
 }
 
+#page {
+    position: relative;
+    width: 94%;
+    margin: 25px 3%;
+    padding: 0;
+}
+
 h1.main,
 h2.main,
 h3.main,
index 754e51a..f7aba5c 100644 (file)
 
 /** Fix IE8 + Opera positioning issue **/
 .ie8 #page-header .rounded-corner.top-right,
+.ie9 #page-header .rounded-corner.top-right,
 .opera #page-header .rounded-corner.top-right {
     position: relative;
     top: -11px;
 }
 
-#page-footer {position: relative;
+#page-footer {
+    position: relative;
 }
+
 #page-footer .rounded-corner {
     position: absolute;
     background-image: url([[pix:theme|corners_header]]);
  * corners.... if only IE could handle it.
  *
  * Browsers:
- * Firefox:          body.gecko
- * Chrome:           body.safari
- * Safari:           body.safari
+ * Firefox:  body.gecko  -moz
+ * Chrome:   body.safari -webkit
+ * Safari:   body.safari -webkit
+ * Opera:    body.opera  no prefix
  */
 
 .opera .rounded-corner.top-left,
 .safari #page-header,
 .gecko .block .corner-box .header,
 .gecko #page-header {
-    -moz-border-radius: 10px 10px 0px 0px;
+    -moz-border-top-left-radius: 10px;
+    -moz-border-top-right-radius: 10px;
     -webkit-border-top-left-radius: 10px;
     -webkit-border-top-right-radius: 10px;
     border-top-left-radius: 10px;
 .opera #page-footer,
 .safari #page-footer,
 .gecko #page-footer {
-    -moz-border-radius: 0px 0px 10px 10px;
+    -moz-border-bottom-left-radius: 10px;
+    -moz-border-bottom-right-radius: 10px;
     -webkit-border-bottom-left-radius: 10px;
     -webkit-border-bottom-right-radius: 10px;
     border-bottom-left-radius: 10px;
     border-bottom-right-radius: 10px;
 }
 
-.gecko .forumpost,
-.gecko .forumpost .side {
-    -moz-border-radius-bottomleft: 20px
+
+.opera.forumpost div.row .left,
+.safari .forumpost div.row .left,
+.gecko .forumpost div.row .left {
+    -moz-border-bottom-left-radius: 20px;
+    -webkit-border-bottom-left-radius: 20px;
+    border-bottom-left-radius: 20px;
 }
 
+.opera .forumpost,
+.opera .forumpost div.row.side,
+.safari .forumpost,
+.safari .forumpost div.row.side,
 .gecko .forumpost,
-.gecko .forumpost .content {
-    -moz-border-radius-bottomright: 20px;
+.gecko .forumpost div.row.side {
+    -moz-border-bottom-right-radius: 20px;
+    -moz-border-bottom-left-radius: 20px;
+    -webkit-border-bottom-right-radius: 20px;
+    -webkit-border-bottom-left-radius: 20px;
+    border-bottom-right-radius: 20px;
+    border-bottom-left-radius: 20px;
+}
+
+.opera .forumpost .options,
+.safari .forumpost .options,
+.gecko .forumpost .options {
+     -moz-border-bottom-right-radius: 20px;
+     -webkit-border-bottom-right-radius: 20px;
+     border-bottom-right-radius: 20px;
+
 }
 
 /** Fix for IE 6 float background bug */
diff --git a/theme/anomaly/style/dock.css b/theme/anomaly/style/dock.css
new file mode 100644 (file)
index 0000000..8c7086d
--- /dev/null
@@ -0,0 +1,138 @@
+/* Docking Module
+-----------------*/
+
+body.has_dock {
+    margin:0;
+}
+
+#dock {
+    width:3%;
+    position:fixed;
+    top:0px;
+    right:0;
+    height:100%;
+    z-index:11000;
+    background-color: #C8C9C7;
+    border-right: 0 none;
+}
+
+#dock.nothingdocked {
+    visibility: hidden;
+    display:none;
+}
+#dock .controls {
+    bottom: auto;
+    background-color: #C8C9C7;
+    -webkit-border-bottom-right-radius: 10px;
+    -moz-border-bottom-right-radius: 10px;
+    border-bottom-right-radius: 10px;
+}
+#dock .dockeditem.firstdockitem {
+    margin-top: 10em;
+    -webkit-border-top-left-radius: 10px;
+    -moz-border-top-right-radius: 10px;
+    border-top-left-radius: 10px;
+}
+#dock .dockeditem {
+    background-color: #C8C9C7;
+    padding: 2px;
+    padding-right: 0px;
+}
+#dock .dockedtitle {
+    padding-bottom: 5px;
+    cursor:pointer;
+    background-color: #222;
+    -webkit-border-top-left-radius: 10px;
+    -moz-border-radius-topleft: 10px;
+    border-top-left-radius: 10px;
+    -webkit-border-bottom-left-radius: 10px;
+    -moz-border-radius-bottomleft: 10px;
+    border-bottom-left-radius: 10px;
+}
+#dock .dockedtitle h2 {
+    margin: 0;
+    padding: 10px 3px;
+    color: #fff;
+    font-family: sans-serif;
+}
+.dockedtitle.activeitem h2 {
+    color: #fff !important;
+}
+#dock .dockedtitle.activeitem {
+    background-color: #697F55;
+    width: 35px;
+    -webkit-border-top-left-radius: 10px;
+    -moz-border-radius-topleft: 10px;
+    border-top-left-radius: 10px;
+    -webkit-border-bottom-left-radius: 10px;
+    -moz-border-radius-bottomleft: 10px;
+    border-bottom-left-radius: 10px;
+}
+#dock .controls img {
+    cursor:pointer;
+    margin-left: 10px;
+}
+/*
+Docked Item Panel
+-----------------------*/
+#dockeditempanel {
+    width: 180px;
+    position: relative;
+    z-index: 12000;
+    left: 100%;
+}
+#dockeditempanel.dockitempanel_hidden {
+    display:none;
+}
+#dockeditempanel .dockeditempanel_content {
+    background-color: #eee;
+    margin: 0 3px;
+    position: relative;
+    min-height: 100px;
+    border-color: #697F55;
+    border-style: solid;
+    border-width: 5px;
+    -webkit-border-radius: 10px;
+    -moz-border-radius: 10px;
+    border-radius: 10px;
+    -webkit-border-top-left-radius: 0;
+    -moz-border-top-left-radius: 0;
+    border-top-left-radius: 0;
+
+}
+#dockeditempanel .dockeditempanel_hd {
+    border-width: 0;
+    background-color: #eee;
+    padding: 2px;
+}
+#dockeditempanel .dockeditempanel_bd .block_docked {
+    margin:10px;
+}
+#dockeditempanel .block_calendar_month.block_docked {
+    text-align: center;
+}
+#dockeditempanel .dockeditempanel_hd {
+    text-align: right;
+    -webkit-border-top-right-radius: 10px;
+    -moz-border-top-right-radius: 10px;
+    border-top-right-radius: 10px;
+}
+#dockeditempanel .dockeditempanel_hd h2 {
+    display:inline;
+    margin: 0;
+    padding-right: 2em;
+    color: #000;
+    float: left;
+}
+
+#dockeditempanel .dockeditempanel_hd .commands {
+    display:inline;
+}
+#dockeditempanel .dockeditempanel_hd .commands img {
+    margin-right: 3px;
+    vertical-align: middle;
+}
+#dockeditempanel .dockeditempanel_bd {
+    overflow:auto;
+    width:auto; /* adds scroll to dock panel */
+}
index df2b251..fc19a6d 100644 (file)
@@ -23,29 +23,43 @@ html, body {
 
 #page-content {
     background-color: #FFF;
+    min-width: 0;
 }
 
+/** Header **/
+
 #page-header {
     background-color: #222;
     color: #FFF;
     border-bottom: 5px solid #697F55;
-}
-.hasnavbar #page-header {
-    border-bottom-width: 0;
+    margin: 0;
+    padding: 0;
+    width: 100%;
 }
 
-#page-footer {
-    background-color: #222;
-    color: #FFF;
+h1.headermain {
+    float: left;
+    font-size: 2.3em;
+    margin: 15px;
+    line-height: 1;
 }
 
 #page-header .headermain span {
     color: #C8C9C7;
 }
 
+/** Navbar **/
+
+.hasnavbar #page-header {
+    border-bottom-color: #3A4D28;
+    border-bottom-width: 3px;
+}
+
 #page-header .navbar {
     background-color: #697F55;
     width: 100%;
+    margin: 0;
+    padding: 0;
 }
 #page-header .navbar {
     color: #000;
@@ -59,6 +73,13 @@ html, body {
     margin: 5px 1em;
 }
 
+/** Footer **/
+
+#page-footer {
+    background-color: #222;
+    color: #FFF;
+}
+
 /** General **/
 .generalbox {
     border: 1px solid #DDDDDD;
@@ -433,45 +454,73 @@ html, body {
 }
 
 /** Forum **/
+
 .forumheaderlist,
 .forumpost {
     margin-top: 15px;
     border: 1px solid #DDD;
     border-collapse: separate;
 }
-.forumpost td {
-    border-width: 0;
+
+.forumpost,
+.forumpost .left.picture {
+    background-color: #EEE;
 }
-.forumpost .topic {
+.forumpost .row .left {
+    float: left;
+    overflow: hidden;
+    width: 43px;
+}
+.forumpost .row.header {
+    background-color: transparent;
+    height: 39px;
+}
+.forumpost .topic.firstpost.starter {
     background-color: #C8C9C7;
 }
-.forumpost .topic .subject {
-    font-weight: bold;
+.forumpost .topic .subject,
+.forumpost .topic .author {
+    padding-left: 10px;
 }
-.forumpost .topic .author {font-size:0.8em;
+
+.forumpost .content,
+.forumpost .options {
+    background-color: white;
+    padding-top: 10px;
 }
-.forumpost .left {
-    background-color: #EEE;
-    padding: 4px;
-    text-align: center;
-    vertical-align: top;
-    width: 35px;
+
+.forumpost .content .shortenedpost a,
+.forumpost .content p {
+    margin: 0 10px;
+    padding: 0;
+}
+.forumpost .options .commands,
+.forumpost .content .attachments,
+.forumpost .options .footer,
+.forumpost .options .link {
+    float: right;
+}
+.forumpost .options .commands,
+.forumpost .options .link {
+    padding-right: 10px;
 }
 
-.forumpost .content .commands {
-    font-size: 0.9em;
-    clear: both;
-    padding-top: 0.5em;
-    text-align: right;
+.forumpost .content .shortenedpost a,
+.forumpost .content .shortenedpost span.post-word-count,
+.forumpost .commands,
+.forumpost .topic .author,
+.forumpost .options .link {
+    font-size: 85%;
+    line-height: 1.6;
 }
-.forumpost .content .link {
-    font-size: 0.9em;
+.forumpost .row .left {
+    clear: left;
 }
 
-.forumpost .content .footer {
-    font-size: 0.9em;
-    padding-top: 0.5em;
-    text-align: right;
+.forumpost .posting.shortenedpost {margin-left: 10px;}
+
+#page-mod-forum-discuss #page-header { /* fixes broken header in forum discuss */
+    margin-top: 10px;
 }
 
 /** Calendar **/
@@ -766,6 +815,10 @@ html, body {
     background-color: #3A4D28;
 }
 
+#custommenu .yui3-menuitem-active .yui3-menuitem-content {
+    background-image: none;
+}
+
 #custommenu .custom_menu_submenu .yui3-menu-label,
 #custommenu .custom_menu_submenu .yui3-menuitem-content {
     line-height: 25px;
@@ -774,6 +827,12 @@ html, body {
 
 #custommenu .yui3-menu-label-active,
 #custommenu .yui3-menu-label-menuvisible,
-#custommenu .yui3-menu .yui3-menu .yui3-menuitem-active .yui3-menuitem-content {
+#custommenu .yui3-menuitem-active .yui3-menuitem-content,
+#custommenu .yui3-menu .yui3-menu .yui3-menuitem-active .yui3-menuitem-content,
+#custommenu .yui3-menu-horizontal.javascript-disabled li a:hover {
     background-color: #697F55;
 }
+
+/* Add Block
+-------------------------*/
+.block .content .singleselect form#add_block .select.menubui_addblock { width: 160px;}
\ No newline at end of file
index 4ff7ea4..1f4b560 100644 (file)
@@ -43,7 +43,7 @@ a.dimmed_text:visited,
 .inline-list li,
 .block .list,
 .block .list li,
-.sitetopic .section li,
+.sitetopic .section li.activity,
 .course-content .section li.activity,
 .tabtree li {list-style: none;margin:0;padding:0;}
 
@@ -743,7 +743,8 @@ body.tag .managelink {padding: 5px;}
 .dir-rtl .mod-indent-15,
 .dir-rtl .mod-indent-huge {margin-right:300px;margin-left:0;}
 
-.dir-rtl .felement.feditor select {margin-right:18.75%;}
+.dir-rtl .felement.feditor select {margin-right:18.75%;margin-left:auto;}
+.dir-rtl .mform .fitem .felement {margin-right: 16%;margin-left:auto;}
 
 /* Resourcelib mp3 player size: only width could be changed here, height hardcoded in JS */
 .resourcecontent .resourcemediaplugin_mp3 object {height:25px; width: 600px}
@@ -821,12 +822,12 @@ sup {vertical-align: super;}
 .path-rating .ratingtable td.time {white-space:nowrap; text-align:center;}
 
 /* Fix for ordered and unordered list in course topic summary & course weekly summary */
-ul li,
-.course-content ul.weeks .content .summary ul li,
-.course-content ul.topics .content .summary ul li {list-style: disc outside none;}
-ol li,
-.course-content ul.weeks .content .summary ol li,
-.course-content ul.topics .content .summary ol li {list-style: decimal outside none;}
+
+.course-content ul.weeks .content .summary ul,
+.course-content ul.topics .content .summary ul {list-style: disc outside none;}
+
+.course-content ul.weeks .content .summary ol,
+.course-content ul.topics .content .summary ol {list-style: decimal outside none;}
 
 .dir-rtl #adminsettings #id_s__pathtodu,
 .dir-rtl #adminsettings #id_s__aspellpath,
index c001976..41bcce9 100644 (file)
@@ -22,6 +22,7 @@ td.grade div.overridden {background-color: #DDDDDD;}
 
 .path-grade-edit-scale .scale_options,
 #page-admin-grade-edit-scale-index .scale_options {font-size: 0.8em;}
+.path-grade-edit-scale .generaltable {margin: 10px auto;}
 
 .gradetreebox {margin:10px auto;width:90%;}
 .gradetreebox table {font-size: 0.8em;border: 1px solid #AAA;}
index 4919d23..e290901 100644 (file)
@@ -57,6 +57,15 @@ if (!empty($CFG->forceloginforprofiles)) {
 
 $userid = $userid ? $userid : $USER->id;       // Owner of the page
 $user = $DB->get_record('user', array('id' => $userid));
+
+if ($user->deleted) {
+    $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
+    echo $OUTPUT->header();
+    echo $OUTPUT->heading(get_string('userdeleted'));
+    echo $OUTPUT->footer();
+    die;
+}
+
 $currentuser = ($user->id == $USER->id);
 $context = $usercontext = get_context_instance(CONTEXT_USER, $userid, MUST_EXIST);
 
index ce82f8e..87f3a00 100644 (file)
@@ -48,7 +48,7 @@ $currentuser = ($user->id == $USER->id);
 
 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
 $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
-$usercontext   = get_context_instance(CONTEXT_USER, $user->id, MUST_EXIST);
+$usercontext   = get_context_instance(CONTEXT_USER, $user->id, IGNORE_MISSING);
 
 // Require login first
 if (isguestuser($user)) {
@@ -68,7 +68,7 @@ $PAGE->set_other_editing_capability('moodle/course:manageactivities');
 
 $isparent = false;
 
-if (!$currentuser
+if (!$currentuser and !$user->deleted
   and $DB->record_exists('role_assignments', array('userid'=>$USER->id, 'contextid'=>$usercontext->id))
   and has_capability('moodle/user:viewdetails', $usercontext)) {
     // TODO: very ugly hack - do not force "parents" to enrol into course their child is enrolled in,
@@ -109,7 +109,7 @@ if ($currentuser) {
 
     // check course level capabilities
     if (!has_capability('moodle/user:viewdetails', $coursecontext) && // normal enrolled user or mnager
-        !has_capability('moodle/user:viewdetails', $usercontext)) {   // usually parent
+        ($user->deleted or !has_capability('moodle/user:viewdetails', $usercontext))) {   // usually parent
         print_error('cannotviewprofile');
     }
 
index 7965e63..c1c40d7 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2011112500.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2011112900.00;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.2beta+ (Build: 20111125)';// Human-friendly version name
+$release  = '2.2beta+ (Build: 20111129)';// Human-friendly version name
 
 $maturity = MATURITY_BETA;              // this version's maturity level
index 86a3f4f..ecb6a9b 100644 (file)
@@ -34,6 +34,124 @@ define('WEBSERVICE_AUTHMETHOD_SESSION_TOKEN', 2);
  */
 class webservice {
 
+    /**
+     * Authenticate user (used by download/upload file scripts)
+     * @param string $token
+     * @return array - contains the authenticated user, token and service objects
+     */
+    public function authenticate_user($token) {
+        global $DB, $CFG;
+
+        // web service must be enabled to use this script
+        if (!$CFG->enablewebservices) {
+            throw new webservice_access_exception(get_string('enablewsdescription', 'webservice'));
+        }
+
+        // Obtain token record
+        if (!$token = $DB->get_record('external_tokens', array('token' => $token))) {
+            throw new webservice_access_exception(get_string('invalidtoken', 'webservice'));
+        }
+
+        // Validate token date
+        if ($token->validuntil and $token->validuntil < time()) {
+            add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '', get_string('invalidtimedtoken', 'webservice'), 0);
+            $DB->delete_records('external_tokens', array('token' => $token->token));
+            throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
+        }
+
+        // Check ip
+        if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) {
+            add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '', get_string('failedtolog', 'webservice') . ": " . getremoteaddr(), 0);
+            throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
+        }
+
+        //retrieve user link to the token
+        $user = $DB->get_record('user', array('id' => $token->userid, 'deleted' => 0), '*', MUST_EXIST);
+
+        // let enrol plugins deal with new enrolments if necessary
+        enrol_check_plugins($user);
+
+        // setup user session to check capability
+        session_set_user($user);
+
+        //assumes that if sid is set then there must be a valid associated session no matter the token type
+        if ($token->sid) {
+            $session = session_get_instance();
+            if (!$session->session_exists($token->sid)) {
+                $DB->delete_records('external_tokens', array('sid' => $token->sid));
+                throw new webservice_access_exception(get_string('invalidtokensession', 'webservice'));
+            }
+        }
+
+        //Non admin can not authenticate if maintenance mode
+        $hassiteconfig = has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM), $user);
+        if (!empty($CFG->maintenance_enabled) and !$hassiteconfig) {
+            throw new webservice_access_exception(get_string('sitemaintenance', 'admin'));
+        }
+
+        //retrieve web service record
+        $service = $DB->get_record('external_services', array('id' => $token->externalserviceid, 'enabled' => 1));
+        if (empty($service)) {
+            // will throw exception if no token found
+            throw new webservice_access_exception(get_string('servicenotavailable', 'webservice'));
+        }
+
+        //check if there is any required system capability
+        if ($service->requiredcapability and !has_capability($service->requiredcapability, get_context_instance(CONTEXT_SYSTEM), $user)) {
+            throw new webservice_access_exception(get_string('missingrequiredcapability', 'webservice', $service->requiredcapability));
+        }
+
+        //specific checks related to user restricted service
+        if ($service->restrictedusers) {
+            $authoriseduser = $DB->get_record('external_services_users', array('externalserviceid' => $service->id, 'userid' => $user->id));
+
+            if (empty($authoriseduser)) {
+                throw new webservice_access_exception(get_string('usernotallowed', 'webservice', $service->name));
+            }
+
+            if (!empty($authoriseduser->validuntil) and $authoriseduser->validuntil < time()) {
+                throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
+            }
+
+            if (!empty($authoriseduser->iprestriction) and !address_in_subnet(getremoteaddr(), $authoriseduser->iprestriction)) {
+                throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
+            }
+        }
+
+        //only confirmed user should be able to call web service
+        if (empty($user->confirmed)) {
+            add_to_log(SITEID, 'webservice', 'user unconfirmed', '', $user->username);
+            throw new webservice_access_exception(get_string('usernotconfirmed', 'moodle', $user->username));
+        }
+
+        //check the user is suspended
+        if (!empty($user->suspended)) {
+            add_to_log(SITEID, 'webservice', 'user suspended', '', $user->username);
+            throw new webservice_access_exception(get_string('usersuspended', 'webservice'));
+        }
+
+        //check if the auth method is nologin (in this case refuse connection)
+        if ($user->auth == 'nologin') {
+            add_to_log(SITEID, 'webservice', 'nologin auth attempt with web service', '', $user->username);
+            throw new webservice_access_exception(get_string('nologinauth', 'webservice'));
+        }
+
+        //Check if the user password is expired
+        $auth = get_auth_plugin($user->auth);
+        if (!empty($auth->config->expiration) and $auth->config->expiration == 1) {
+            $days2expire = $auth->password_expire($user->username);
+            if (intval($days2expire) < 0) {
+                add_to_log(SITEID, 'webservice', 'expired password', '', $user->username);
+                throw new webservice_access_exception(get_string('passwordisexpired', 'webservice'));
+            }
+        }
+
+        // log token access
+        $DB->set_field('external_tokens', 'lastaccess', time(), array('id' => $token->id));
+
+        return array('user' => $user, 'token' => $token, 'service' => $service);
+    }
+
     /**
      * Add a user to the list of authorised user of a given service
      * @param object $user
diff --git a/webservice/pluginfile.php b/webservice/pluginfile.php
new file mode 100644 (file)
index 0000000..186e36e
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * A script to serve files from web service client
+ *
+ * @package    core
+ * @subpackage file
+ * @copyright  2011 Dongsheng Cai <dongsheng@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('AJAX_SCRIPT', true);
+define('NO_MOODLE_COOKIES', true);
+require_once(dirname(dirname(__FILE__)) . '/config.php');
+require_once($CFG->libdir . '/filelib.php');
+require_once($CFG->dirroot . '/webservice/lib.php');
+
+//authenticate the user
+$token = required_param('token', PARAM_ALPHANUM);
+$webservicelib = new webservice();
+$authenticationinfo = $webservicelib->authenticate_user($token);
+
+//check the service allows file download
+$enabledfiledownload = (int) ($authenticationinfo['service']->downloadfiles);
+if (empty($enabledfiledownload)) {
+    throw new webservice_access_exception(get_string('enabledirectdownload', 'webservice'));
+}
+
+//finally we can serve the file :)
+$relativepath = get_file_argument();
+file_pluginfile($relativepath, 0);
index 629f312..1b4e3e8 100644 (file)
@@ -74,7 +74,8 @@ class webservice_test extends UnitTestCase {
             'moodle_enrol_get_enrolled_users' => false,
             'moodle_group_get_course_groups' => false,
             'moodle_group_get_groupmembers' => false,
-            'moodle_webservice_get_siteinfo' => false
+            'moodle_webservice_get_siteinfo' => false,
+            'core_course_get_contents' => false
         );
 
         ////// WRITE DB tests ////
@@ -247,6 +248,26 @@ class webservice_test extends UnitTestCase {
         $this->assertEqual(count($users), count($userids));
     }
 
+    function core_course_get_contents($client) {
+        global $DB, $CFG;
+        $dbcourses = $DB->get_records('course');
+        $function = 'core_course_get_contents';
+
+        $coursecontents = array();
+
+        foreach ($dbcourses as $dbcourse) {
+            $params = array('courseid' => $dbcourse->id);
+
+            if (file_exists($CFG->dirroot . '/' . '/course/format/' . $dbcourse->format . '/lib.php')) {
+                $coursecontents = $client->call($function, $params);
+            }
+
+            //Display the content of $coursecontents in your php log and check if you obtain
+            //what you are expecting
+            //error_log(print_r($coursecontents, true));
+        }
+    }
+
     /**
      * This test will:
      * 1- create a user (core call)
index 874b03e..6219e37 100644 (file)
 define('AJAX_SCRIPT', true);
 define('NO_MOODLE_COOKIES', true);
 require_once(dirname(dirname(__FILE__)) . '/config.php');
-$token = required_param('token', PARAM_ALPHANUM);
+require_once($CFG->dirroot . '/webservice/lib.php');
 $filepath = optional_param('filepath', '/', PARAM_PATH);
 
 echo $OUTPUT->header();
 
-// web service must be enabled to use this script
-if (!$CFG->enablewebservices) {
-    throw new moodle_exception('enablewsdescription', 'webservice');
-}
-// Obtain token record
-if (!$token = $DB->get_record('external_tokens', array('token'=>$token))) {
-    throw new webservice_access_exception(get_string('invalidtoken', 'webservice'));
-}
-
-// Validate token date
-if ($token->validuntil and $token->validuntil < time()) {
-    add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '' , get_string('invalidtimedtoken', 'webservice'), 0);
-    $DB->delete_records('external_tokens', array('token'=>$token->token));
-    throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
-}
-
-//assumes that if sid is set then there must be a valid associated session no matter the token type
-if ($token->sid) {
-    $session = session_get_instance();
-    if (!$session->session_exists($token->sid)) {
-        $DB->delete_records('external_tokens', array('sid'=>$token->sid));
-        throw new webservice_access_exception(get_string('invalidtokensession', 'webservice'));
-    }
-}
-
-// Check ip
-if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) {
-    add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '' , get_string('failedtolog', 'webservice').": ".getremoteaddr(), 0);
-    throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
-}
-
-$user = $DB->get_record('user', array('id'=>$token->userid, 'deleted'=>0), '*', MUST_EXIST);
-
-// log token access
-$DB->set_field('external_tokens', 'lastaccess', time(), array('id'=>$token->id));
+//authenticate the user
+$token = required_param('token', PARAM_ALPHANUM);
+$webservicelib = new webservice();
+$authenticationinfo = $webservicelib->authenticate_user($token);
 
-// let enrol plugins deal with new enrolments if necessary
-enrol_check_plugins($user);
-session_set_user($user);
+//check the user can manage his own files (can upload)
 $context = get_context_instance(CONTEXT_USER, $USER->id);
 require_capability('moodle/user:manageownfiles', $context);
 
@@ -148,7 +115,7 @@ foreach ($files as $file) {
     $file_record->filepath  = $filepath;
     $file_record->itemid    = 0;
     $file_record->license   = $CFG->sitedefaultlicense;
-    $file_record->author    = fullname($user);;
+    $file_record->author    = fullname($authenticationinfo['user']);;
     $file_record->source    = '';
     $stored_file = $fs->create_file_from_pathname($file_record, $file->filepath);
     $results[] = $file_record;