Merge branch 'm28_MDL-46325' of git://github.com/totara/moodle
authorMarina Glancy <marina@moodle.com>
Tue, 29 Jul 2014 03:58:24 +0000 (11:58 +0800)
committerMarina Glancy <marina@moodle.com>
Tue, 29 Jul 2014 03:58:24 +0000 (11:58 +0800)
242 files changed:
admin/index.php
admin/renderer.php
admin/settings/users.php
admin/tool/behat/tests/behat/data_generators.feature
admin/tool/behat/tests/behat/manipulate_forms.feature
admin/tool/uploaduser/user_form.php
auth/cas/auth.php
backup/moodle2/restore_stepslib.php
backup/util/helper/restore_logs_processor.class.php
backup/util/ui/backup_ui_setting.class.php
badges/edit_form.php
blocks/login/block_login.php
blog/edit.php
blog/edit_form.php
blog/external_blog_edit.php
blog/external_blog_edit_form.php
blog/external_blogs.php
blog/index.php
blog/lib.php
blog/locallib.php
blog/preferences.php
blog/preferences_form.php
blog/renderer.php
blog/rsslib.php
blog/tests/bloglib_test.php
cache/admin.php
cache/classes/helper.php
cache/classes/store.php
cache/locallib.php
cache/renderer.php
cache/stores/memcache/lang/en/cachestore_memcache.php
cache/stores/memcache/lib.php
cache/stores/memcached/lang/en/cachestore_memcached.php
cache/stores/memcached/lib.php
calendar/event_form.php
calendar/lib.php
calendar/tests/lib_test.php
course/classes/management/helper.php
course/classes/management_renderer.php
course/lib.php
course/management.php
course/renderer.php
course/tests/behat/category_resort.feature
course/tests/behat/course_category_management_listing.feature
course/tests/behat/course_resort.feature
enrol/category/db/access.php
enrol/category/lang/en/enrol_category.php
enrol/category/lib.php
enrol/category/version.php
enrol/cohort/lib.php
enrol/cohort/version.php
enrol/cohort/yui/quickenrolment/quickenrolment.js
enrol/database/db/access.php
enrol/database/lang/en/enrol_database.php
enrol/database/lib.php
enrol/database/version.php
enrol/flatfile/lib.php
enrol/flatfile/version.php
enrol/guest/lib.php
enrol/guest/version.php
enrol/imsenterprise/db/access.php [new file with mode: 0644]
enrol/imsenterprise/lang/en/enrol_imsenterprise.php
enrol/imsenterprise/lib.php
enrol/imsenterprise/version.php
enrol/instances.php
enrol/ldap/lib.php
enrol/ldap/version.php
enrol/manual/lib.php
enrol/manual/version.php
enrol/meta/lib.php
enrol/meta/version.php
enrol/mnet/db/access.php [new file with mode: 0644]
enrol/mnet/lang/en/enrol_mnet.php
enrol/mnet/lib.php
enrol/mnet/version.php
enrol/paypal/lib.php
enrol/paypal/version.php
enrol/self/lib.php
enrol/self/version.php
enrol/upgrade.txt
files/renderer.php
filter/activitynames/filter.php
filter/tex/filter.php
filter/tex/lang/en/filter_tex.php
filter/tex/latex.php
filter/tex/lib.php
filter/tex/pix.php
filter/tex/settings.php
filter/tex/texdebug.php
group/autogroup.php
group/autogroup_form.php
group/lib.php
group/tests/behat/auto_creation.feature
install/lang/af/moodle.php [new file with mode: 0644]
install/lang/ru/install.php
install/lang/te/install.php
install/lang/uk/admin.php
install/lang/vi/admin.php
lang/en/admin.php
lang/en/group.php
lang/en/moodle.php
lib/authlib.php
lib/classes/collator.php
lib/classes/event/recent_activity_viewed.php
lib/classes/grades_external.php
lib/classes/task/adhoc_task.php
lib/classes/task/manager.php
lib/classes/task/scheduled_task.php
lib/completionlib.php
lib/coursecatlib.php
lib/csvlib.class.php
lib/db/install.xml
lib/db/upgrade.php
lib/editor/atto/plugins/accessibilitychecker/lang/en/atto_accessibilitychecker.php
lib/editor/atto/plugins/accessibilitychecker/lib.php
lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature
lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js
lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js
lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js
lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js
lib/enrollib.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/form/filemanager.js
lib/htmlpurifier/locallib.php
lib/moodlelib.php
lib/outputcomponents.php
lib/outputrenderers.php
lib/testing/generator/data_generator.php
lib/tests/behat/behat_data_generators.php
lib/tests/collator_test.php
lib/tests/coursecatlib_test.php
lib/tests/htmlpurifier_test.php
lib/upgrade.txt
lib/weblib.php
lib/yui/build/moodle-core-dock/moodle-core-dock-debug.js
lib/yui/build/moodle-core-dock/moodle-core-dock-min.js
lib/yui/build/moodle-core-dock/moodle-core-dock.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js
lib/yui/build/moodle-core-notification-alert/moodle-core-notification-alert-debug.js
lib/yui/build/moodle-core-notification-alert/moodle-core-notification-alert-min.js
lib/yui/build/moodle-core-notification-alert/moodle-core-notification-alert.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-debug.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-min.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js
lib/yui/src/dock/js/dock.js
lib/yui/src/notification/js/ajaxexception.js
lib/yui/src/notification/js/alert.js
lib/yui/src/notification/js/confirm.js
lib/yui/src/notification/js/exception.js
login/index.php
login/index_form.html
message/lib.php
message/tests/messagelib_test.php
mod/assign/backup/moodle2/backup_assign_stepslib.php
mod/assign/backup/moodle2/restore_assign_stepslib.php
mod/assign/db/access.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/mod_form.php
mod/assign/renderable.php
mod/assign/renderer.php
mod/assign/tests/base_test.php
mod/assign/tests/locallib_test.php
mod/assign/version.php
mod/feedback/item/textarea/lib.php
mod/feedback/item/textfield/lib.php
mod/forum/classes/event/user_report_viewed.php
mod/forum/discuss.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/renderer.php
mod/forum/styles.css
mod/forum/tests/behat/discussion_navigation.feature [new file with mode: 0644]
mod/forum/tests/lib_test.php
mod/quiz/backup/moodle2/backup_quiz_stepslib.php
mod/quiz/db/install.xml
mod/quiz/db/upgrade.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/mod_form.php
mod/quiz/tests/behat/completion_condition_attempts_used.feature [new file with mode: 0644]
mod/quiz/tests/behat/completion_condition_passing_grade.feature [new file with mode: 0644]
mod/quiz/version.php
mod/scorm/datamodels/aicc.js [moved from mod/scorm/datamodels/aicc.js.php with 56% similarity]
mod/scorm/datamodels/aicc.php [new file with mode: 0644]
mod/scorm/datamodels/aicclib.php
mod/scorm/datamodels/debug.js.php
mod/scorm/datamodels/scorm_12.js [moved from mod/scorm/datamodels/scorm_12.js.php with 54% similarity]
mod/scorm/datamodels/scorm_12.php [new file with mode: 0644]
mod/scorm/datamodels/scorm_12lib.php
mod/scorm/datamodels/scorm_13.js [moved from mod/scorm/datamodels/scorm_13.js.php with 77% similarity]
mod/scorm/datamodels/scorm_13.php [new file with mode: 0644]
mod/scorm/datamodels/scorm_13lib.php
mod/scorm/loaddatamodel.php [deleted file]
mod/scorm/locallib.php
mod/scorm/module.js
mod/scorm/player.php
mod/scorm/version.php
mod/scorm/view.php
mod/survey/classes/event/report_downloaded.php
mod/survey/classes/event/report_viewed.php
mod/wiki/pagelib.php
mod/wiki/tests/behat/wiki_comments.feature [new file with mode: 0644]
notes/delete.php
notes/edit.php
notes/edit_form.php
notes/externallib.php
notes/index.php
notes/lib.php
question/qengine.js
rating/index.php
rating/lib.php
rating/module.js
rating/rate.php
rating/rate_ajax.php
rating/tests/rating_test.php
report/eventlist/tests/behat/mainsection.feature
report/outline/classes/event/activity_report_viewed.php
report/outline/classes/event/report_viewed.php
repository/filepicker.js
rss/file.php
rss/index.html [deleted file]
rss/renderer.php
theme/base/style/core.css
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/filemanager.less
theme/bootstrapbase/style/moodle.css
user/editlib.php
user/externallib.php
user/filters/lib.php
user/lib.php
user/profile.php
user/view.php
version.php

index aaa530a..34c0f95 100644 (file)
@@ -589,10 +589,14 @@ $availableupdatesfetch = $updateschecker->get_last_timefetched();
 $buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
 //check if the site is registered on Moodle.org
 $registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
+// Check if there are any cache warnings.
+$cachewarnings = cache_helper::warnings();
 
 admin_externalpage_setup('adminnotifications');
 
+/* @var core_admin_renderer $output */
 $output = $PAGE->get_renderer('core', 'admin');
-echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
-        $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
-        $registered);
+
+echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
+                                       $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
+                                       $registered, $cachewarnings);
index 954b977..99109a2 100644 (file)
@@ -303,12 +303,13 @@ class core_admin_renderer extends plugin_renderer_base {
      * @param bool $buggyiconvnomb warn iconv problems
      * @param array|null $availableupdates array of \core\update\info objects or null
      * @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
+     * @param string[] $cachewarnings An array containing warnings from the Cache API.
      *
      * @return string HTML to output.
      */
     public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
             $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
-            $buggyiconvnomb, $registered) {
+            $buggyiconvnomb, $registered, array $cachewarnings = array()) {
         global $CFG;
         $output = '';
 
@@ -321,6 +322,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $output .= $this->cron_overdue_warning($cronoverdue);
         $output .= $this->db_problems($dbproblems);
         $output .= $this->maintenance_mode_warning($maintenancemode);
+        $output .= $this->cache_warnings($cachewarnings);
         $output .= $this->registration_warning($registered);
 
         //////////////////////////////////////////////////////////////////////////////////////////////////
@@ -595,6 +597,19 @@ class core_admin_renderer extends plugin_renderer_base {
         return $this->warning($dbproblems);
     }
 
+    /**
+     * Renders cache warnings if there are any.
+     *
+     * @param string[] $cachewarnings
+     * @return string
+     */
+    public function cache_warnings(array $cachewarnings) {
+        if (!count($cachewarnings)) {
+            return '';
+        }
+        return join("\n", array_map(array($this, 'warning'), $cachewarnings));
+    }
+
     /**
      * Render an appropriate message if the site in in maintenance mode.
      * @param bool $maintenancemode
index 2231bab..5a7e75a 100644 (file)
@@ -24,6 +24,46 @@ if ($hassiteconfig
     $ADMIN->add('accounts', new admin_externalpage('editusers', new lang_string('userlist','admin'), "$CFG->wwwroot/$CFG->admin/user.php", array('moodle/user:update', 'moodle/user:delete')));
     $ADMIN->add('accounts', new admin_externalpage('userbulk', new lang_string('userbulk','admin'), "$CFG->wwwroot/$CFG->admin/user/user_bulk.php", array('moodle/user:update', 'moodle/user:delete')));
     $ADMIN->add('accounts', new admin_externalpage('addnewuser', new lang_string('addnewuser'), "$securewwwroot/user/editadvanced.php?id=-1", 'moodle/user:create'));
+
+    // "User default preferences" settingpage.
+    $temp = new admin_settingpage('userdefaultpreferences', new lang_string('userdefaultpreferences', 'admin'));
+    if ($ADMIN->fulltree) {
+        $choices = array();
+        $choices['0'] = new lang_string('emaildisplayno');
+        $choices['1'] = new lang_string('emaildisplayyes');
+        $choices['2'] = new lang_string('emaildisplaycourse');
+        $temp->add(new admin_setting_configselect('defaultpreference_maildisplay', new lang_string('emaildisplay'),
+            '', 2, $choices));
+
+        $choices = array();
+        $choices['0'] = new lang_string('textformat');
+        $choices['1'] = new lang_string('htmlformat');
+        $temp->add(new admin_setting_configselect('defaultpreference_mailformat', new lang_string('emailformat'), '', 1, $choices));
+
+        $choices = array();
+        $choices['0'] = new lang_string('emaildigestoff');
+        $choices['1'] = new lang_string('emaildigestcomplete');
+        $choices['2'] = new lang_string('emaildigestsubjects');
+        $temp->add(new admin_setting_configselect('defaultpreference_maildigest', new lang_string('emaildigest'),
+            new lang_string('emaildigest_help'), 0, $choices));
+
+
+        $choices = array();
+        $choices['1'] = new lang_string('autosubscribeyes');
+        $choices['0'] = new lang_string('autosubscribeno');
+        $temp->add(new admin_setting_configselect('defaultpreference_autosubscribe', new lang_string('autosubscribe'),
+            '', 1, $choices));
+
+        if (!empty($CFG->forum_trackreadposts)) {
+            $choices = array();
+            $choices['0'] = new lang_string('trackforumsno');
+            $choices['1'] = new lang_string('trackforumsyes');
+            $temp->add(new admin_setting_configselect('defaultpreference_trackforums', new lang_string('trackforums'),
+                '', 0, $choices));
+        }
+    }
+    $ADMIN->add('accounts', $temp);
+
     $ADMIN->add('accounts', new admin_externalpage('profilefields', new lang_string('profilefields','admin'), "$CFG->wwwroot/user/profile/index.php", 'moodle/site:config'));
     $ADMIN->add('accounts', new admin_externalpage('cohorts', new lang_string('cohorts', 'cohort'), $CFG->wwwroot . '/cohort/index.php', array('moodle/cohort:manage', 'moodle/cohort:view')));
 
index 3561419..2b9dfdf 100644 (file)
@@ -252,3 +252,25 @@ Feature: Set up contextual data for tests
     And the "members" select box should contain "Student 1"
     And I set the field "groups" to "Group 2 (1)"
     And the "members" select box should contain "Student 2"
+
+  Scenario: Add cohorts with data generator
+    Given the following "categories" exist:
+      | name  | category | idnumber |
+      | Cat 1 | 0        | CAT1     |
+    And the following "cohorts" exist:
+      | name            | idnumber |
+      | System cohort 1 | CH01     |
+    And the following "cohorts" exist:
+      | name                 | idnumber | contextlevel | reference |
+      | System cohort 2      | CH02     | System       |           |
+      | Cohort in category 1 | CH1      | Category     | CAT1      |
+    When I log in as "admin"
+    And I navigate to "Cohorts" node in "Site administration > Users > Accounts"
+    Then I should see "System cohort 1"
+    And I should see "System cohort 2"
+    And I should not see "Cohort in category"
+    And I follow "Courses"
+    And I follow "Cat 1"
+    And I follow "Cohorts"
+    And I should see "Cohort in category 1"
+    And I should not see "System cohort"
index 3696b81..952b65a 100644 (file)
@@ -11,6 +11,7 @@ Feature: Forms manipulation
     When I set the field "First name" to "Field value"
     And I set the field "Text editor" to "Plain text area"
     And I set the field "Unmask" to "1"
+    And I expand all fieldsets
     Then the field "First name" matches value "Field value"
     And the "Text editor" select box should contain "Plain text area"
     And the field "Unmask" matches value "1"
index f922995..1ec16e0 100644 (file)
@@ -221,21 +221,21 @@ class admin_uploaduser_form2 extends moodleform {
 
         $choices = array(0 => get_string('emaildisplayno'), 1 => get_string('emaildisplayyes'), 2 => get_string('emaildisplaycourse'));
         $mform->addElement('select', 'maildisplay', get_string('emaildisplay'), $choices);
-        $mform->setDefault('maildisplay', 2);
+        $mform->setDefault('maildisplay', $CFG->defaultpreference_maildisplay);
 
         $choices = array(0 => get_string('textformat'), 1 => get_string('htmlformat'));
         $mform->addElement('select', 'mailformat', get_string('emailformat'), $choices);
-        $mform->setDefault('mailformat', 1);
+        $mform->setDefault('mailformat', $CFG->defaultpreference_mailformat);
         $mform->setAdvanced('mailformat');
 
         $choices = array(0 => get_string('emaildigestoff'), 1 => get_string('emaildigestcomplete'), 2 => get_string('emaildigestsubjects'));
         $mform->addElement('select', 'maildigest', get_string('emaildigest'), $choices);
-        $mform->setDefault('maildigest', 0);
+        $mform->setDefault('maildigest', $CFG->defaultpreference_maildigest);
         $mform->setAdvanced('maildigest');
 
         $choices = array(1 => get_string('autosubscribeyes'), 0 => get_string('autosubscribeno'));
         $mform->addElement('select', 'autosubscribe', get_string('autosubscribe'), $choices);
-        $mform->setDefault('autosubscribe', 1);
+        $mform->setDefault('autosubscribe', $CFG->defaultpreference_autosubscribe);
 
         $mform->addElement('text', 'city', get_string('city'), 'maxlength="120" size="25"');
         $mform->setType('city', PARAM_TEXT);
index 6615b75..9d83dd1 100644 (file)
@@ -111,6 +111,26 @@ class auth_plugin_cas extends auth_plugin_ldap {
             return;
         }
 
+        // If the multi-authentication setting is used, check for the param before connecting to CAS.
+        if ($this->config->multiauth) {
+            $authCAS = optional_param('authCAS', '', PARAM_RAW);
+            if ($authCAS == 'NOCAS') {
+                return;
+            }
+            // Show authentication form for multi-authentication.
+            // Test pgtIou parameter for proxy mode (https connection in background from CAS server to the php server).
+            if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
+                $PAGE->set_url('/login/index.php');
+                $PAGE->navbar->add($CASform);
+                $PAGE->set_title("$site->fullname: $CASform");
+                $PAGE->set_heading($site->fullname);
+                echo $OUTPUT->header();
+                include($CFG->dirroot.'/auth/cas/cas_form.html');
+                echo $OUTPUT->footer();
+                exit();
+            }
+        }
+
         // Connection to CAS server
         $this->connectCAS();
 
@@ -134,27 +154,6 @@ class auth_plugin_cas extends auth_plugin_ldap {
             return;
         }
 
-        if ($this->config->multiauth) {
-            $authCAS = optional_param('authCAS', '', PARAM_RAW);
-            if ($authCAS == 'NOCAS') {
-                return;
-            }
-
-            // Show authentication form for multi-authentication
-            // test pgtIou parameter for proxy mode (https connection
-            // in background from CAS server to the php server)
-            if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
-                $PAGE->set_url('/login/index.php');
-                $PAGE->navbar->add($CASform);
-                $PAGE->set_title("$site->fullname: $CASform");
-                $PAGE->set_heading($site->fullname);
-                echo $OUTPUT->header();
-                include($CFG->dirroot.'/auth/cas/cas_form.html');
-                echo $OUTPUT->footer();
-                exit();
-            }
-        }
-
         // Force CAS authentication (if needed).
         if (!phpCAS::isAuthenticated()) {
             phpCAS::setLang($this->config->language);
index 6e7a461..d0036cf 100644 (file)
@@ -2609,7 +2609,18 @@ class restore_course_logs_structure_step extends restore_structure_step {
 
         // If we have data, insert it, else something went wrong in the restore_logs_processor
         if ($data) {
-            $DB->insert_record('log', $data);
+            if (empty($data->url)) {
+                $data->url = '';
+            }
+            if (empty($data->info)) {
+                $data->info = '';
+            }
+            // Store the data in the legacy log table if we are still using it.
+            $manager = get_log_manager();
+            if (method_exists($manager, 'legacy_add_to_log')) {
+                $manager->legacy_add_to_log($data->course, $data->module, $data->action, $data->url,
+                    $data->info, $data->cmid, $data->userid);
+            }
         }
     }
 }
@@ -2647,7 +2658,18 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure
 
         // If we have data, insert it, else something went wrong in the restore_logs_processor
         if ($data) {
-            $DB->insert_record('log', $data);
+            if (empty($data->url)) {
+                $data->url = '';
+            }
+            if (empty($data->info)) {
+                $data->info = '';
+            }
+            // Store the data in the legacy log table if we are still using it.
+            $manager = get_log_manager();
+            if (method_exists($manager, 'legacy_add_to_log')) {
+                $manager->legacy_add_to_log($data->course, $data->module, $data->action, $data->url,
+                    $data->info, $data->cmid, $data->userid);
+            }
         }
     }
 }
index 63ff801..585d9b4 100644 (file)
@@ -89,11 +89,11 @@ class restore_logs_processor {
             }
             // Arrived here log is empty, no rule was able to perform the conversion, log the problem
             if (empty($newlog)) {
-                self::$task->log('Log module-action "' . $keyname . ' process problem. Not restored', backup::LOG_DEBUG);
+                self::$task->log('Log module-action "' . $keyname . '" process problem. Not restored', backup::LOG_DEBUG);
             }
 
         } else { // Action not found log the problem
-            self::$task->log('Log module-action "' . $keyname . ' unknown. Not restored', backup::LOG_DEBUG);
+            self::$task->log('Log module-action "' . $keyname . '" unknown. Not restored', backup::LOG_DEBUG);
             $newlog = false;
 
         }
index 9ef5865..1712a73 100644 (file)
@@ -139,7 +139,8 @@ class base_setting_ui {
      * @param string $label
      */
     public function set_label($label) {
-        if ((string)$label === '' || $label !== clean_param($label, PARAM_TEXT)) {
+        $label = (string)$label;
+        if ($label === '' || $label !== clean_param($label, PARAM_TEXT)) {
             throw new base_setting_ui_exception('setting_invalid_ui_label');
         }
         $this->label = $label;
index 24e52d7..cebc483 100644 (file)
@@ -54,7 +54,7 @@ class edit_details_form extends moodleform {
         $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $mform->addElement('textarea', 'description', get_string('description', 'badges'), 'wrap="virtual" rows="8" cols="70"');
-        $mform->setType('description', PARAM_CLEANHTML);
+        $mform->setType('description', PARAM_NOTAGS);
         $mform->addRule('description', null, 'required');
 
         $str = $action == 'new' ? get_string('badgeimage', 'badges') : get_string('newimage', 'badges');
index be63064..2c4eda4 100644 (file)
@@ -70,10 +70,15 @@ class block_login extends block_base {
         $this->content->text = '';
 
         if (!isloggedin() or isguestuser()) {   // Show the block
+            if (empty($CFG->authloginviaemail)) {
+                $strusername = get_string('username');
+            } else {
+                $strusername = get_string('usernameemail');
+            }
 
             $this->content->text .= "\n".'<form class="loginform" id="login" method="post" action="'.get_login_url().'" '.$autocomplete.'>';
 
-            $this->content->text .= '<div class="c1 fld username"><label for="login_username">'.get_string('username').'</label>';
+            $this->content->text .= '<div class="c1 fld username"><label for="login_username">'.$strusername.'</label>';
             $this->content->text .= '<input type="text" name="username" id="login_username" value="'.s($username).'" /></div>';
 
             $this->content->text .= '<div class="c1 fld password"><label for="login_password">'.get_string('password').'</label>';
index fadc8ad..c3052f7 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 require_once(dirname(dirname(__FILE__)).'/config.php');
-include_once('lib.php');
-include_once('locallib.php');
+require_once('lib.php');
+require_once('locallib.php');
 
 $action   = required_param('action', PARAM_ALPHA);
 $id       = optional_param('entryid', 0, PARAM_INT);
 $confirm  = optional_param('confirm', 0, PARAM_BOOL);
-$modid    = optional_param('modid', 0, PARAM_INT); // To associate the entry with a module instance
-$courseid = optional_param('courseid', 0, PARAM_INT); // To associate the entry with a course
-
-$PAGE->set_url('/blog/edit.php', array('action' => $action, 'entryid' => $id, 'confirm' => $confirm, 'modid' => $modid, 'courseid' => $courseid));
+$modid = optional_param('modid', 0, PARAM_INT); // To associate the entry with a module instance.
+$courseid = optional_param('courseid', 0, PARAM_INT); // To associate the entry with a course.
 
-// If action is add, we ignore $id to avoid any further problems
-if (!empty($id) && $action == 'add') {
-    $id = null;
+if ($action == 'edit') {
+    $id = required_param('entryid', PARAM_INT);
 }
 
-$returnurl = new moodle_url('/blog/index.php');
+$PAGE->set_url('/blog/edit.php', array('action' => $action,
+                                       'entryid' => $id,
+                                       'confirm' => $confirm,
+                                       'modid' => $modid,
+                                       'courseid' => $courseid));
 
-if (!empty($courseid) && empty($modid)) {
-    $returnurl->param('courseid', $courseid);
-}
-
-// If a modid is given, guess courseid
-if (!empty($modid)) {
-    $returnurl->param('modid', $modid);
-    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
-    $returnurl->param('courseid', $courseid);
+// If action is add, we ignore $id to avoid any further problems.
+if (!empty($id) && $action == 'add') {
+    $id = null;
 }
 
 // Blogs are always in system context.
 $sitecontext = context_system::instance();
 $PAGE->set_context($sitecontext);
 
-
-$blogheaders = blog_get_headers();
-
 require_login($courseid);
 
-if ($action == 'edit') {
-    $id = required_param('entryid', PARAM_INT);
-}
-
 if (empty($CFG->enableblogs)) {
     print_error('blogdisable', 'blog');
 }
@@ -75,11 +62,26 @@ if (isguestuser()) {
     print_error('noguestentry', 'blog');
 }
 
+$returnurl = new moodle_url('/blog/index.php');
+
+if (!empty($courseid) && empty($modid)) {
+    $returnurl->param('courseid', $courseid);
+}
+
+// If a modid is given, guess courseid.
+if (!empty($modid)) {
+    $returnurl->param('modid', $modid);
+    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
+    $returnurl->param('courseid', $courseid);
+}
+
+$blogheaders = blog_get_headers();
+
 if (!has_capability('moodle/blog:create', $sitecontext) && !has_capability('moodle/blog:manageentries', $sitecontext)) {
     print_error('cannoteditentryorblog');
 }
 
-// Make sure that the person trying to edit has access right
+// Make sure that the person trying to edit has access right.
 if ($id) {
     if (!$entry = new blog_entry($id)) {
         print_error('wrongentryid', 'blog');
@@ -94,7 +96,7 @@ if ($id) {
 
 } else {
     if (!has_capability('moodle/blog:create', $sitecontext)) {
-        print_error('noentry', 'blog'); // manageentries is not enough for adding
+        print_error('noentry', 'blog'); // The capability "manageentries" is not enough for adding.
     }
     $entry  = new stdClass();
     $entry->id = null;
@@ -105,14 +107,14 @@ $returnurl->param('userid', $userid);
 // Blog renderer.
 $output = $PAGE->get_renderer('blog');
 
-$strblogs = get_string('blogs','blog');
+$strblogs = get_string('blogs', 'blog');
 
-if ($action === 'delete'){
+if ($action === 'delete') {
     if (empty($entry->id)) {
         print_error('wrongentryid', 'blog');
     }
     if (data_submitted() && $confirm && confirm_sesskey()) {
-        // Make sure the current user is the author of the blog entry, or has some deleteanyentry capability
+        // Make sure the current user is the author of the blog entry, or has some deleteanyentry capability.
         if (!blog_user_can_edit_entry($entry)) {
             print_error('nopermissionstodeleteentry', 'blog');
         } else {
@@ -132,7 +134,9 @@ if ($action === 'delete'){
         echo $output->render($entry);
 
         echo '<br />';
-        echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'), new moodle_url('edit.php', $optionsyes),new moodle_url( 'index.php', $optionsno));
+        echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'),
+                              new moodle_url('edit.php', $optionsyes),
+                              new moodle_url('index.php', $optionsno));
         echo $OUTPUT->footer();
         die;
     }
@@ -167,10 +171,21 @@ $summaryoptions = array('maxfiles'=> 99, 'maxbytes'=>$CFG->maxbytes, 'trusttext'
     'subdirs'=>file_area_contains_subdirs($sitecontext, 'blog', 'post', $entry->id));
 $attachmentoptions = array('subdirs'=>false, 'maxfiles'=> 99, 'maxbytes'=>$CFG->maxbytes);
 
-$blogeditform = new blog_edit_form(null, compact('entry', 'summaryoptions', 'attachmentoptions', 'sitecontext', 'courseid', 'modid'));
+$blogeditform = new blog_edit_form(null, compact('entry',
+                                                 'summaryoptions',
+                                                 'attachmentoptions',
+                                                 'sitecontext',
+                                                 'courseid',
+                                                 'modid'));
 
 $entry = file_prepare_standard_editor($entry, 'summary', $summaryoptions, $sitecontext, 'blog', 'post', $entry->id);
-$entry = file_prepare_standard_filemanager($entry, 'attachment', $attachmentoptions, $sitecontext, 'blog', 'attachment', $entry->id);
+$entry = file_prepare_standard_filemanager($entry,
+                                           'attachment',
+                                           $attachmentoptions,
+                                           $sitecontext,
+                                           'blog',
+                                           'attachment',
+                                           $entry->id);
 
 if (!empty($CFG->usetags) && !empty($entry->id)) {
     include_once($CFG->dirroot.'/tag/lib.php');
@@ -178,13 +193,13 @@ if (!empty($CFG->usetags) && !empty($entry->id)) {
 }
 
 $entry->action = $action;
-// set defaults
+// Set defaults.
 $blogeditform->set_data($entry);
 
 if ($blogeditform->is_cancelled()) {
     redirect($returnurl);
 
-} else if ($data = $blogeditform->get_data()){
+} else if ($data = $blogeditform->get_data()) {
 
     switch ($action) {
         case 'add':
@@ -209,23 +224,23 @@ if ($blogeditform->is_cancelled()) {
 }
 
 
-// gui setup
+// GUI setup.
 switch ($action) {
     case 'add':
-        // prepare new empty form
+        // Prepare new empty form.
         $entry->publishstate = 'site';
         $strformheading = get_string('addnewentry', 'blog');
         $entry->action       = $action;
 
         if ($CFG->useblogassociations) {
 
-            //pre-select the course for associations
+            // Pre-select the course for associations.
             if ($courseid) {
                 $context = context_course::instance($courseid);
                 $entry->courseassoc = $context->id;
             }
 
-            //pre-select the mod for associations
+            // Pre-select the mod for associations.
             if ($modid) {
                 $context = context_module::instance($modid);
                 $entry->modassoc = $context->id;
index 2b28a73..805bf79 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -16,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');    //  It must be included from a Moodle page.
 }
 
 require_once($CFG->libdir.'/formslib.php');
@@ -24,7 +23,10 @@ require_once($CFG->libdir.'/formslib.php');
 class blog_edit_form extends moodleform {
     public $modnames = array();
 
-    function definition() {
+    /**
+     * Blog form definition.
+     */
+    public function definition() {
         global $CFG, $DB;
 
         $mform =& $this->_form;
@@ -50,12 +52,12 @@ class blog_edit_form extends moodleform {
 
         $mform->addElement('filemanager', 'attachment_filemanager', get_string('attachment', 'forum'), null, $attachmentoptions);
 
-        //disable publishstate options that are not allowed
+        // Disable publishstate options that are not allowed.
         $publishstates = array();
         $i = 0;
 
         foreach (blog_entry::get_applicable_publish_states() as $state => $desc) {
-            $publishstates[$state] = $desc;   //no maximum was set
+            $publishstates[$state] = $desc;   // No maximum was set.
             $i++;
         }
 
@@ -87,7 +89,12 @@ class blog_edit_form extends moodleform {
                 }
 
                 $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));
+                $mform->addElement('advcheckbox',
+                                   'courseassoc',
+                                   get_string('associatewithcourse', 'blog', $a),
+                                   null,
+                                   null,
+                                   array(0, $contextid));
                 $mform->setDefault('courseassoc', $contextid);
 
             } else if ((!empty($entry->modassoc) || !empty($modid))) {
@@ -107,7 +114,12 @@ class blog_edit_form extends moodleform {
                 }
 
                 $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
+                $mform->addElement('advcheckbox',
+                                   'modassoc',
+                                   get_string('associatewithmodule', 'blog', $a),
+                                   null,
+                                   null,
+                                   array(0, $context->id));
                 $mform->setDefault('modassoc', $context->id);
             }
         }
@@ -130,12 +142,18 @@ class blog_edit_form extends moodleform {
         $mform->setDefault('courseid', $courseid);
     }
 
-    function validation($data, $files) {
+    /**
+     * Validate the blog form data.
+     * @param array $data Data to be validated
+     * @param array $files unused
+     * @return array|bool
+     */
+    public function validation($data, $files) {
         global $CFG, $DB, $USER;
 
         $errors = array();
 
-        // validate course association
+        // Validate course association.
         if (!empty($data['courseassoc'])) {
             $coursecontext = context::instance_by_id($data['courseassoc']);
 
@@ -144,16 +162,16 @@ class blog_edit_form extends moodleform {
             }
         }
 
-        // validate mod association
+        // Validate mod association.
         if (!empty($data['modassoc'])) {
             $modcontextid = $data['modassoc'];
             $modcontext = context::instance_by_id($modcontextid);
 
             if ($modcontext->contextlevel == CONTEXT_MODULE) {
-                // get context of the mod's course
+                // Get context of the mod's course.
                 $coursecontext = $modcontext->get_course_context(true);
 
-                // ensure only one course is associated
+                // Ensure only one course is associated.
                 if (!empty($data['courseassoc'])) {
                     if ($data['courseassoc'] != $coursecontext->id) {
                         $errors['modassoc'] = get_string('onlyassociateonecourse', 'blog');
index b28860a..0aa122b 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -35,7 +34,9 @@ require_login();
 $context = context_system::instance();
 require_capability('moodle/blog:manageexternal', $context);
 
-// TODO redirect if $CFG->useexternalblogs is off, $CFG->maxexternalblogsperuser == 0, or if user doesn't have caps to manage external blogs
+// TODO redirect if $CFG->useexternalblogs is off,
+//                  $CFG->maxexternalblogsperuser == 0,
+//                  or if user doesn't have caps to manage external blogs.
 
 $id = optional_param('id', null, PARAM_INT);
 $url = new moodle_url('/blog/external_blog_edit.php');
@@ -52,24 +53,24 @@ $action = (empty($id)) ? 'add' : 'edit';
 
 $external = new stdClass();
 
-// Check that this id exists
+// Check that this id exists.
 if (!empty($id) && !$DB->record_exists('blog_external', array('id' => $id))) {
     print_error('wrongexternalid', 'blog');
-} elseif (!empty($id)) {
+} else if (!empty($id)) {
     $external = $DB->get_record('blog_external', array('id' => $id));
 }
 
 $strformheading = ($action == 'edit') ? get_string('editexternalblog', 'blog') : get_string('addnewexternalblog', 'blog');
-$strexternalblogs = get_string('externalblogs','blog');
-$strblogs = get_string('blogs','blog');
+$strexternalblogs = get_string('externalblogs', 'blog');
+$strblogs = get_string('blogs', 'blog');
 
 $externalblogform = new blog_edit_external_form();
 
-if ($externalblogform->is_cancelled()){
+if ($externalblogform->is_cancelled()) {
     redirect($returnurl);
 
 } else if ($data = $externalblogform->get_data()) {
-    //save stuff in db
+    // Save stuff in db.
     switch ($action) {
         case 'add':
             $rss = new moodle_simplepie($data->url);
@@ -79,13 +80,16 @@ if ($externalblogform->is_cancelled()){
             $newexternal->description = (empty($data->description)) ? $rss->get_description() : $data->description;
             $newexternal->userid = $USER->id;
             $newexternal->url = $data->url;
-            $newexternal->filtertags = $data->filtertags;
+            $newexternal->filtertags = (!empty($data->filtertags)) ? $data->filtertags : null;
             $newexternal->timemodified = time();
 
             $newexternal->id = $DB->insert_record('blog_external', $newexternal);
             blog_sync_external_entries($newexternal);
-            tag_set('blog_external', $newexternal->id, explode(',', $data->autotags), 'core',
-                context_user::instance($newexternal->userid)->id);
+            if ($CFG->usetags) {
+                $autotags = (!empty($data->autotags)) ? $data->autotags : null;
+                tag_set('blog_external', $newexternal->id, explode(',', $autotags), 'core',
+                    context_user::instance($newexternal->userid)->id);
+            }
 
             break;
 
@@ -99,13 +103,15 @@ if ($externalblogform->is_cancelled()){
                 $external->description = (empty($data->description)) ? $rss->get_description() : $data->description;
                 $external->userid = $USER->id;
                 $external->url = $data->url;
-                $external->filtertags = $data->filtertags;
+                $external->filtertags = (!empty($data->filtertags)) ? $data->filtertags : null;
                 $external->timemodified = time();
 
                 $DB->update_record('blog_external', $external);
-                tag_set('blog_external', $external->id, explode(',', $data->autotags), 'core',
-                    context_user::instance($newexternal->userid)->id);
-
+                if ($CFG->usetags) {
+                    $autotags = (!empty($data->autotags)) ? $data->autotags : null;
+                    tag_set('blog_external', $external->id, explode(',', $autotags), 'core',
+                        context_user::instance($external->userid)->id);
+                }
             } else {
                 print_error('wrongexternalid', 'blog');
             }
index 696e79a..fc28e9a 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -26,7 +25,7 @@
  */
 
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');    // It must be included from a Moodle page.
 }
 
 require_once($CFG->libdir.'/formslib.php');
@@ -118,9 +117,11 @@ class blog_edit_external_form extends moodleform {
         if ($id = $mform->getElementValue('id')) {
             $mform->setDefault('autotags', implode(',', tag_get_tags_array('blog_external', $id)));
             $mform->freeze('url');
-            $mform->freeze('filtertags');
+            if ($mform->elementExists('filtertags')) {
+                $mform->freeze('filtertags');
+            }
             // TODO change the filtertags element to a multiple select, using the tags of the external blog
-            // Use $rss->get_channel_tags()
+            // Use $rss->get_channel_tags().
         }
     }
 }
index 57af11a..800c85c 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -36,23 +35,25 @@ require_capability('moodle/blog:manageexternal', $context);
 
 $delete = optional_param('delete', null, PARAM_INT);
 
-$strexternalblogs = get_string('externalblogs','blog');
-$straddnewexternalblog = get_string('addnewexternalblog','blog');
-$strblogs = get_string('blogs','blog');
+$strexternalblogs = get_string('externalblogs', 'blog');
+$straddnewexternalblog = get_string('addnewexternalblog', 'blog');
+$strblogs = get_string('blogs', 'blog');
 $message = null;
 
 if ($delete && confirm_sesskey()) {
     $externalbloguserid = $DB->get_field('blog_external', 'userid', array('id' => $delete));
     if ($externalbloguserid == $USER->id) {
-        // Delete the external blog
+        // Delete the external blog.
         $DB->delete_records('blog_external', array('id' => $delete));
 
-        // Delete the external blog's posts
+        // Delete the external blog's posts.
         $deletewhere = 'module = :module
                             AND userid = :userid
                             AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false) . '
                             AND ' . $DB->sql_compare_text('content') . ' = ' . $DB->sql_compare_text(':delete');
-        $DB->delete_records_select('post', $deletewhere, array('module' => 'blog_external', 'userid' => $USER->id, 'delete' => $delete));
+        $DB->delete_records_select('post', $deletewhere, array('module' => 'blog_external',
+                                                               'userid' => $USER->id,
+                                                               'delete' => $delete));
 
         $message = get_string('externalblogdeleted', 'blog');
     }
@@ -77,7 +78,11 @@ if (!empty($blogs)) {
     $table = new html_table();
     $table->cellpadding = 4;
     $table->attributes['class'] = 'generaltable boxaligncenter';
-    $table->head = array(get_string('name'), get_string('url', 'blog'), get_string('timefetched', 'blog'), get_string('valid', 'blog'), get_string('actions'));
+    $table->head = array(get_string('name'),
+                         get_string('url', 'blog'),
+                         get_string('timefetched', 'blog'),
+                         get_string('valid', 'blog'),
+                         get_string('actions'));
 
     foreach ($blogs as $blog) {
         if ($blog->failedlastsync) {
@@ -92,7 +97,11 @@ if (!empty($blogs)) {
         $deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey'=>sesskey()));
         $deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')));
 
-        $table->data[] = new html_table_row(array($blog->name, $blog->url, userdate($blog->timefetched), $validicon, $editicon . '&nbsp'. $deleteicon));
+        $table->data[] = new html_table_row(array($blog->name,
+                                                  $blog->url,
+                                                  userdate($blog->timefetched),
+                                                  $validicon,
+                                                  $editicon . '&nbsp'. $deleteicon));
     }
     echo html_writer::table($table);
 }
index efa99ea..4c58f34 100644 (file)
@@ -1,4 +1,18 @@
 <?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/>.
 
 /**
  * file index.php
@@ -34,11 +48,7 @@ foreach ($url_params as $var => $val) {
 }
 $PAGE->set_url('/blog/index.php', $url_params);
 
-if (empty($CFG->enableblogs)) {
-    print_error('blogdisable', 'blog');
-}
-
-//correct tagid if a text tag is provided as a param
+// Correct tagid if a text tag is provided as a param.
 if (!empty($tag)) {
     if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
         $tagid = $tagrec->id;
@@ -47,43 +57,47 @@ if (!empty($tag)) {
     }
 }
 
-// add courseid if modid or groupid is specified: This is used for navigation and title
-if (!empty($modid) && empty($courseid)) {
-    $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
-}
-
-if (!empty($groupid) && empty($courseid)) {
-    $courseid = $DB->get_field('groups', 'courseid', array('id'=>$groupid));
-}
-
 $sitecontext = context_system::instance();
 // Blogs are always in system context.
 $PAGE->set_context($sitecontext);
 
-// check basic permissions
+// Check basic permissions.
 if ($CFG->bloglevel == BLOG_GLOBAL_LEVEL) {
-    // everybody can see anything - no login required unless site is locked down using forcelogin
+    // Everybody can see anything - no login required unless site is locked down using forcelogin.
     if ($CFG->forcelogin) {
         require_login();
     }
 
 } else if ($CFG->bloglevel == BLOG_SITE_LEVEL) {
-    // users must log in and can not be guests
+    // Users must log in and can not be guests.
     require_login();
     if (isguestuser()) {
-        // they must have entered the url manually...
+        // They must have entered the url manually.
         print_error('blogdisable', 'blog');
     }
 
 } else if ($CFG->bloglevel == BLOG_USER_LEVEL) {
-    // users can see own blogs only! with the exception of ppl with special cap
+    // Users can see own blogs only! with the exception of people with special cap.
     require_login();
 
 } else {
-    // weird!
+    // Weird!
     print_error('blogdisable', 'blog');
 }
 
+if (empty($CFG->enableblogs)) {
+    print_error('blogdisable', 'blog');
+}
+
+// Add courseid if modid or groupid is specified: This is used for navigation and title.
+if (!empty($modid) && empty($courseid)) {
+    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
+}
+
+if (!empty($groupid) && empty($courseid)) {
+    $courseid = $DB->get_field('groups', 'courseid', array('id' => $groupid));
+}
+
 
 if (!$userid && has_capability('moodle/blog:view', $sitecontext) && $CFG->bloglevel > BLOG_USER_LEVEL) {
     if ($entryid) {
@@ -206,13 +220,10 @@ if ($CFG->enablerssfeeds) {
     }
     $rsstitle = $blogheaders['heading'];
 
-    //check we haven't started output by outputting an error message
+    // Check we haven't started output by outputting an error message.
     if ($PAGE->state == moodle_page::STATE_BEFORE_HEADER) {
         blog_rss_add_http_header($rsscontext, $rsstitle, $filtertype, $thingid, $tagid);
     }
-
-    //this works but there isn't a great place to put the link
-    //blog_rss_print_link($rsscontext, $filtertype, $thingid, $tagid);
 }
 
 echo $OUTPUT->header();
index 9190e46..b9cbae5 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -26,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-/**
+/*
  * Library of functions and constants for blog
  */
 require_once($CFG->dirroot .'/blog/rsslib.php');
@@ -45,11 +44,11 @@ function blog_user_can_edit_entry($blogentry) {
     $sitecontext = context_system::instance();
 
     if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-        return true; // can edit any blog entry
+        return true; // Can edit any blog entry.
     }
 
     if ($blogentry->userid == $USER->id && has_capability('moodle/blog:create', $sitecontext)) {
-        return true; // can edit own when having blog:create capability
+        return true; // Can edit own when having blog:create capability.
     }
 
     return false;
@@ -168,12 +167,12 @@ function blog_sync_external_entries($externalblog) {
     if (empty($rss->data)) {
         return null;
     }
-    //used to identify blog posts that have been deleted from the source feed
+    // Used to identify blog posts that have been deleted from the source feed.
     $oldesttimestamp = null;
     $uniquehashes = array();
 
     foreach ($rss->get_items() as $entry) {
-        // If filtertags are defined, use them to filter the entries by RSS category
+        // If filtertags are defined, use them to filter the entries by RSS category.
         if (!empty($externalblog->filtertags)) {
             $containsfiltertag = false;
             $categories = $entry->get_categories();
@@ -181,9 +180,11 @@ function blog_sync_external_entries($externalblog) {
             $filtertags = array_map('trim', $filtertags);
             $filtertags = array_map('strtolower', $filtertags);
 
-            foreach ($categories as $category) {
-                if (in_array(trim(strtolower($category->term)), $filtertags)) {
-                    $containsfiltertag = true;
+            if (!empty($categories)) {
+                foreach ($categories as $category) {
+                    if (in_array(trim(strtolower($category->term)), $filtertags)) {
+                        $containsfiltertag = true;
+                    }
                 }
             }
 
@@ -201,26 +202,26 @@ function blog_sync_external_entries($externalblog) {
         $newentry->uniquehash = $entry->get_permalink();
         $newentry->publishstate = 'site';
         $newentry->format = FORMAT_HTML;
-        // Clean subject of html, just in case
+        // Clean subject of html, just in case.
         $newentry->subject = clean_param($entry->get_title(), PARAM_TEXT);
-        // Observe 128 max chars in DB
-        // TODO: +1 to raise this to 255
+        // Observe 128 max chars in DB.
+        // TODO: +1 to raise this to 255.
         if (core_text::strlen($newentry->subject) > 128) {
             $newentry->subject = core_text::substr($newentry->subject, 0, 125) . '...';
         }
         $newentry->summary = $entry->get_description();
 
-        //used to decide whether to insert or update
-        //uses enty permalink plus creation date if available
+        // Used to decide whether to insert or update.
+        // Uses enty permalink plus creation date if available.
         $existingpostconditions = array('uniquehash' => $entry->get_permalink());
 
-        //our DB doesnt allow null creation or modified timestamps so check the external blog supplied one
+        // Our DB doesnt allow null creation or modified timestamps so check the external blog supplied one.
         $entrydate = $entry->get_date('U');
         if (!empty($entrydate)) {
             $existingpostconditions['created'] = $entrydate;
         }
 
-        //the post ID or false if post not found in DB
+        // The post ID or false if post not found in DB.
         $postid = $DB->get_field('post', 'id', $existingpostconditions);
 
         $timestamp = null;
@@ -230,14 +231,14 @@ function blog_sync_external_entries($externalblog) {
             $timestamp = $entrydate;
         }
 
-        //only set created if its a new post so we retain the original creation timestamp if the post is edited
+        // Only set created if its a new post so we retain the original creation timestamp if the post is edited.
         if ($postid === false) {
             $newentry->created = $timestamp;
         }
         $newentry->lastmodified = $timestamp;
 
         if (empty($oldesttimestamp) || $timestamp < $oldesttimestamp) {
-            //found an older post
+            // Found an older post.
             $oldesttimestamp = $timestamp;
         }
 
@@ -252,7 +253,7 @@ function blog_sync_external_entries($externalblog) {
         if ($postid === false) {
             $id = $DB->insert_record('post', $newentry);
 
-            // Set tags
+            // Set tags.
             if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) {
                 tag_set('post', $id, $tags, 'core', context_user::instance($externalblog->userid)->id);
             }
@@ -273,7 +274,7 @@ function blog_sync_external_entries($externalblog) {
     $dbposts = $DB->get_records_sql($sql, array('blogid' => $externalblog->id, 'ts' => $oldesttimestamp));
 
     $todelete = array();
-    foreach($dbposts as $dbpost) {
+    foreach ($dbposts as $dbpost) {
         if ( !in_array($dbpost->uniquehash, $uniquehashes) ) {
             $todelete[] = $dbpost->id;
         }
@@ -324,13 +325,13 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
 
     $options = array();
 
-    // If blogs are enabled and the user is logged in and not a guest
+    // If blogs are enabled and the user is logged in and not a guest.
     if (blog_is_enabled_for_user()) {
-        // If the context is the user then assume we want to load for the users context
+        // If the context is the user then assume we want to load for the users context.
         if (is_null($userid) && $page->context->contextlevel == CONTEXT_USER) {
             $userid = $page->context->instanceid;
         }
-        // Check the userid var
+        // Check the userid var.
         if (!is_null($userid) && $userid!==$USER->id) {
             // Load the user from the userid... it MUST EXIST throw a wobbly if it doesn't!
             $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
@@ -339,33 +340,36 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
         }
 
         if ($CFG->useblogassociations && $page->cm !== null) {
-            // Load for the module associated with the page
+            // Load for the module associated with the page.
             $options[CONTEXT_MODULE] = blog_get_options_for_module($page->cm, $user);
         } else if ($CFG->useblogassociations && $page->course->id != SITEID) {
-            // Load the options for the course associated with the page
+            // Load the options for the course associated with the page.
             $options[CONTEXT_COURSE] = blog_get_options_for_course($page->course, $user);
         }
 
-        // Get the options for the user
+        // Get the options for the user.
         if ($user !== null and !isguestuser($user)) {
-            // Load for the requested user
+            // Load for the requested user.
             $options[CONTEXT_USER+1] = blog_get_options_for_user($user);
         }
-        // Load for the current user
+        // Load for the current user.
         if (isloggedin() and !isguestuser()) {
             $options[CONTEXT_USER] = blog_get_options_for_user();
         }
     }
 
-    // If blog level is global then display a link to view all site entries
-    if (!empty($CFG->enableblogs) && $CFG->bloglevel >= BLOG_GLOBAL_LEVEL && has_capability('moodle/blog:view', context_system::instance())) {
+    // If blog level is global then display a link to view all site entries.
+    if (!empty($CFG->enableblogs)
+        && $CFG->bloglevel >= BLOG_GLOBAL_LEVEL
+        && has_capability('moodle/blog:view', context_system::instance())) {
+
         $options[CONTEXT_SYSTEM] = array('viewsite' => array(
             'string' => get_string('viewsiteentries', 'blog'),
             'link' => new moodle_url('/blog/index.php')
         ));
     }
 
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -380,16 +384,16 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
  */
 function blog_get_options_for_user(stdClass $user=null) {
     global $CFG, $USER;
-    // Cache
+    // Cache.
     static $useroptions = array();
 
     $options = array();
-    // Blogs must be enabled and the user must be logged in
+    // Blogs must be enabled and the user must be logged in.
     if (!blog_is_enabled_for_user()) {
         return $options;
     }
 
-    // Sort out the user var
+    // Sort out the user var.
     if ($user === null || $user->id == $USER->id) {
         $user = $USER;
         $iscurrentuser = true;
@@ -397,7 +401,7 @@ function blog_get_options_for_user(stdClass $user=null) {
         $iscurrentuser = false;
     }
 
-    // If we've already generated serve from the cache
+    // If we've already generated serve from the cache.
     if (array_key_exists($user->id, $useroptions)) {
         return $useroptions[$user->id];
     }
@@ -406,22 +410,22 @@ function blog_get_options_for_user(stdClass $user=null) {
     $canview = has_capability('moodle/blog:view', $sitecontext);
 
     if (!$iscurrentuser && $canview && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
-        // Not the current user, but we can view and its blogs are enabled for SITE or GLOBAL
+        // Not the current user, but we can view and its blogs are enabled for SITE or GLOBAL.
         $options['userentries'] = array(
             'string' => get_string('viewuserentries', 'blog', fullname($user)),
             'link' => new moodle_url('/blog/index.php', array('userid'=>$user->id))
         );
     } else {
-        // It's the current user
+        // It's the current user.
         if ($canview) {
-            // We can view our own blogs .... BIG surprise
+            // We can view our own blogs .... BIG surprise.
             $options['view'] = array(
                 'string' => get_string('viewallmyentries', 'blog'),
                 'link' => new moodle_url('/blog/index.php', array('userid'=>$USER->id))
             );
         }
         if (has_capability('moodle/blog:create', $sitecontext)) {
-            // We can add to our own blog
+            // We can add to our own blog.
             $options['add'] = array(
                 'string' => get_string('addnewentry', 'blog'),
                 'link' => new moodle_url('/blog/edit.php', array('action'=>'add'))
@@ -432,12 +436,12 @@ function blog_get_options_for_user(stdClass $user=null) {
         $options['rss'] = array(
             'string' => get_string('rssfeed', 'blog'),
             'link' => new moodle_url(rss_get_url($sitecontext->id, $USER->id, 'blog', 'user/'.$user->id))
-       );
+        );
     }
 
-    // Cache the options
+    // Cache the options.
     $useroptions[$user->id] = $options;
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -451,47 +455,46 @@ function blog_get_options_for_user(stdClass $user=null) {
  */
 function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
     global $CFG, $USER;
-    // Cache
+    // Cache.
     static $courseoptions = array();
 
     $options = array();
 
-    // User must be logged in and blogs must be enabled
+    // User must be logged in and blogs must be enabled.
     if (!blog_is_enabled_for_user()) {
         return $options;
     }
 
-    // Check that the user can associate with the course
+    // Check that the user can associate with the course.
     $sitecontext = context_system::instance();
-    // Generate the cache key
+    // Generate the cache key.
     $key = $course->id.':';
     if (!empty($user)) {
         $key .= $user->id;
     } else {
         $key .= $USER->id;
     }
-    // Serve from the cache if we've already generated for this course
+    // Serve from the cache if we've already generated for this course.
     if (array_key_exists($key, $courseoptions)) {
         return $courseoptions[$key];
     }
 
-
     if (has_capability('moodle/blog:view', $sitecontext)) {
         // We can view!
         if ($CFG->bloglevel >= BLOG_SITE_LEVEL) {
-            // View entries about this course
+            // View entries about this course.
             $options['courseview'] = array(
                 'string' => get_string('viewcourseblogs', 'blog'),
                 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id))
             );
         }
-        // View MY entries about this course
+        // View MY entries about this course.
         $options['courseviewmine'] = array(
             'string' => get_string('viewmyentriesaboutcourse', 'blog'),
             'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id, 'userid' => $USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
-            // View the provided users entries about this course
+            // View the provided users entries about this course.
             $options['courseviewuser'] = array(
                 'string' => get_string('viewentriesbyuseraboutcourse', 'blog', fullname($user)),
                 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id, 'userid' => $user->id))
@@ -500,17 +503,16 @@ function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
     }
 
     if (has_capability('moodle/blog:create', $sitecontext)) {
-        // We can blog about this course
+        // We can blog about this course.
         $options['courseadd'] = array(
             'string' => get_string('blogaboutthiscourse', 'blog'),
             'link' => new moodle_url('/blog/edit.php', array('action' => 'add', 'courseid' => $course->id))
         );
     }
 
-
-    // Cache the options for this course
+    // Cache the options for this course.
     $courseoptions[$key] = $options;
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -524,18 +526,18 @@ function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
  */
 function blog_get_options_for_module($module, $user=null) {
     global $CFG, $USER;
-    // Cache
+    // Cache.
     static $moduleoptions = array();
 
     $options = array();
-    // User must be logged in, blogs must be enabled
+    // User must be logged in, blogs must be enabled.
     if (!blog_is_enabled_for_user()) {
         return $options;
     }
 
     $sitecontext = context_system::instance();
 
-    // Generate the cache key
+    // Generate the cache key.
     $key = $module->id.':';
     if (!empty($user)) {
         $key .= $user->id;
@@ -543,18 +545,17 @@ function blog_get_options_for_module($module, $user=null) {
         $key .= $USER->id;
     }
     if (array_key_exists($key, $moduleoptions)) {
-        // Serve from the cache so we don't have to regenerate
+        // Serve from the cache so we don't have to regenerate.
         return $moduleoptions[$key];
     }
 
-
     if (has_capability('moodle/blog:view', $sitecontext)) {
         // Save correct module name for later usage.
         $modulename = get_string('modulename', $module->modname);
 
         // We can view!
         if ($CFG->bloglevel >= BLOG_SITE_LEVEL) {
-            // View all entries about this module
+            // View all entries about this module.
             $a = new stdClass;
             $a->type = $modulename;
             $options['moduleview'] = array(
@@ -562,13 +563,13 @@ function blog_get_options_for_module($module, $user=null) {
                 'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id))
             );
         }
-        // View MY entries about this module
+        // View MY entries about this module.
         $options['moduleviewmine'] = array(
             'string' => get_string('viewmyentriesaboutmodule', 'blog', $modulename),
             'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id, 'userid'=>$USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
-            // View the given users entries about this module
+            // View the given users entries about this module.
             $a = new stdClass;
             $a->mod = $modulename;
             $a->user = fullname($user);
@@ -580,15 +581,15 @@ function blog_get_options_for_module($module, $user=null) {
     }
 
     if (has_capability('moodle/blog:create', $sitecontext)) {
-        // The user can blog about this module
+        // The user can blog about this module.
         $options['moduleadd'] = array(
             'string' => get_string('blogaboutthismodule', 'blog', $modulename),
             'link' => new moodle_url('/blog/edit.php', array('action'=>'add', 'modid'=>$module->id))
         );
     }
-    // Cache the options
+    // Cache the options.
     $moduleoptions[$key] = $options;
-    // Return the options
+    // Return the options.
     return $options;
 }
 
@@ -626,7 +627,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
     $action   = optional_param('action', null, PARAM_ALPHA);
     $confirm  = optional_param('confirm', false, PARAM_BOOL);
 
-    // Ignore userid when action == add
+    // Ignore userid when action == add.
     if ($action == 'add' && $userid) {
         unset($userid);
         $PAGE->url->remove_params(array('userid'));
@@ -644,11 +645,11 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
     $site = $DB->get_record('course', array('id' => SITEID));
     $sitecontext = context_system::instance();
-    // Common Lang strings
+    // Common Lang strings.
     $strparticipants = get_string("participants");
     $strblogentries  = get_string("blogentries", 'blog');
 
-    // Prepare record objects as needed
+    // Prepare record objects as needed.
     if (!empty($courseid)) {
         $headers['filters']['course'] = $courseid;
         $course = $DB->get_record('course', array('id' => $courseid));
@@ -659,7 +660,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $user = $DB->get_record('user', array('id' => $userid));
     }
 
-    if (!empty($groupid)) { // groupid always overrides courseid
+    if (!empty($groupid)) { // The groupid always overrides courseid.
         $headers['filters']['group'] = $groupid;
         $group = $DB->get_record('groups', array('id' => $groupid));
         $course = $DB->get_record('course', array('id' => $group->courseid));
@@ -667,11 +668,11 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
     $PAGE->set_pagelayout('standard');
 
-    // modid always overrides courseid, so the $course object may be reset here
+    // The modid always overrides courseid, so the $course object may be reset here.
     if (!empty($modid) && $CFG->useblogassociations) {
 
         $headers['filters']['module'] = $modid;
-        // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case
+        // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case.
         $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
         $course = $DB->get_record('course', array('id' => $courseid));
         $cm = $DB->get_record('course_modules', array('id' => $modid));
@@ -685,17 +686,16 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
     }
 
     // Case 1: No entry, mod, course or user params: all site entries to be shown (filtered by search and tag/tagid)
-    // Note: if action is set to 'add' or 'edit', we do this at the end
+    // Note: if action is set to 'add' or 'edit', we do this at the end.
     if (empty($entryid) && empty($modid) && empty($courseid) && empty($userid) && !in_array($action, array('edit', 'add'))) {
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $PAGE->navbar->add($strblogentries, $blogurl);
         $PAGE->set_title("$shortname: " . get_string('blog', 'blog'));
         $PAGE->set_heading("$shortname: " . get_string('blog', 'blog'));
         $headers['heading'] = get_string('siteblog', 'blog', $shortname);
-        // $headers['strview'] = get_string('viewsiteentries', 'blog');
     }
 
-    // Case 2: only entryid is requested, ignore all other filters. courseid is used to give more contextual information
+    // Case 2: only entryid is requested, ignore all other filters. courseid is used to give more contextual information.
     if (!empty($entryid)) {
         $headers['filters']['entry'] = $entryid;
         $sql = 'SELECT u.* FROM {user} u, {post} p WHERE p.id = ? AND p.userid = u.id';
@@ -720,15 +720,16 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $PAGE->set_heading("$shortname: " . fullname($user) . ": $entry->subject");
         $headers['heading'] = get_string('blogentrybyuser', 'blog', fullname($user));
 
-        // We ignore tag and search params
+        // We ignore tag and search params.
         if (empty($action) || !$CFG->useblogassociations) {
             $headers['url'] = $blogurl;
             return $headers;
         }
     }
 
-    // Case 3: A user's blog entries
     if (!empty($userid) && empty($entryid) && ((empty($courseid) && empty($modid)) || !$CFG->useblogassociations)) {
+        // Case 3: A user's blog entries.
+
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $blogurl->param('userid', $userid);
         $PAGE->set_title("$shortname: " . fullname($user) . ": " . get_string('blog', 'blog'));
@@ -736,23 +737,21 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['heading'] = get_string('userblog', 'blog', fullname($user));
         $headers['strview'] = get_string('viewuserentries', 'blog', fullname($user));
 
-    } else
+    } else if (!$CFG->useblogassociations && empty($userid) && !in_array($action, array('edit', 'add'))) {
+        // Case 4: No blog associations, no userid.
 
-    // Case 4: No blog associations, no userid
-    if (!$CFG->useblogassociations && empty($userid) && !in_array($action, array('edit', 'add'))) {
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $PAGE->set_title("$shortname: " . get_string('blog', 'blog'));
         $PAGE->set_heading("$shortname: " . get_string('blog', 'blog'));
         $headers['heading'] = get_string('siteblog', 'blog', $shortname);
-    } else
+    } else if (!empty($userid) && !empty($modid) && empty($entryid)) {
+        // Case 5: Blog entries associated with an activity by a specific user (courseid ignored).
 
-    // Case 5: Blog entries associated with an activity by a specific user (courseid ignored)
-    if (!empty($userid) && !empty($modid) && empty($entryid)) {
         $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $blogurl->param('userid', $userid);
         $blogurl->param('modid', $modid);
 
-        // Course module navigation is handled by build_navigation as the second param
+        // Course module navigation is handled by build_navigation as the second param.
         $headers['cm'] = $cm;
         $PAGE->navbar->add(fullname($user), "$CFG->wwwroot/user/view.php?id=$user->id");
         $PAGE->navbar->add($strblogentries, $blogurl);
@@ -767,10 +766,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['heading'] = get_string('blogentriesbyuseraboutmodule', 'blog', $a);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewallmodentries', 'blog', $a);
-    } else
+    } else if (!empty($userid) && !empty($courseid) && empty($modid) && empty($entryid)) {
+        // Case 6: Blog entries associated with a course by a specific user.
 
-    // Case 6: Blog entries associated with a course by a specific user
-    if (!empty($userid) && !empty($courseid) && empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $blogurl->param('userid', $userid);
@@ -789,12 +787,11 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
 
-        // Remove the userid from the URL to inform the blog_menu block correctly
+        // Remove the userid from the URL to inform the blog_menu block correctly.
         $blogurl->remove_params(array('userid'));
-    } else
+    } else if (!empty($groupid) && empty($modid) && empty($entryid)) {
+        // Case 7: Blog entries by members of a group, associated with that group's course.
 
-    // Case 7: Blog entries by members of a group, associated with that group's course
-    if (!empty($groupid) && empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $blogurl->param('courseid', $course->id);
@@ -814,10 +811,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['heading'] = get_string('blogentriesbygroupaboutcourse', 'blog', $a);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
-    } else
+    } else if (!empty($groupid) && !empty($modid) && empty($entryid)) {
+        // Case 8: Blog entries by members of a group, associated with an activity in that course.
 
-    // Case 8: Blog entries by members of a group, associated with an activity in that course
-    if (!empty($groupid) && !empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $headers['cm'] = $cm;
@@ -838,10 +834,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewallmodentries', 'blog', $a);
 
-    } else
+    } else if (!empty($modid) && empty($userid) && empty($groupid) && empty($entryid)) {
+        // Case 9: All blog entries associated with an activity.
 
-    // Case 9: All blog entries associated with an activity
-    if (!empty($modid) && empty($userid) && empty($groupid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $PAGE->set_cm($cm, $course);
@@ -854,10 +849,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $a->type = get_string('modulename', $cm->modname);
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewallmodentries', 'blog', $a);
-    } else
+    } else if (!empty($courseid) && empty($userid) && empty($groupid) && empty($modid) && empty($entryid)) {
+        // Case 10: All blog entries associated with a course.
 
-    // Case 10: All blog entries associated with a course
-    if (!empty($courseid) && empty($userid) && empty($groupid) && empty($modid) && empty($entryid)) {
         $siteshortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID)));
         $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
         $blogurl->param('courseid', $courseid);
@@ -866,20 +860,24 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         $PAGE->set_heading("$siteshortname: $courseshortname: " . get_string('blogentries', 'blog'));
         $a = new stdClass();
         $a->type = get_string('course');
-        $headers['heading'] = get_string('blogentriesabout', 'blog', format_string($course->fullname, true, array('context' => context_course::instance($course->id))));
+        $headers['heading'] = get_string('blogentriesabout',
+                                         'blog',
+                                         format_string($course->fullname,
+                                                       true,
+                                                       array('context' => context_course::instance($course->id))));
         $headers['stradd'] = get_string('blogaboutthis', 'blog', $a);
         $headers['strview'] = get_string('viewblogentries', 'blog', $a);
         $blogurl->remove_params(array('userid'));
     }
 
     if (!in_array($action, array('edit', 'add'))) {
-        // Append Tag info
+        // Append Tag info.
         if (!empty($tagid)) {
             $headers['filters']['tag'] = $tagid;
             $blogurl->param('tagid', $tagid);
             $tagrec = $DB->get_record('tag', array('id'=>$tagid));
             $PAGE->navbar->add($tagrec->name, $blogurl);
-        } elseif (!empty($tag)) {
+        } else if (!empty($tag)) {
             if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
                 $tagid = $tagrec->id;
                 $headers['filters']['tag'] = $tagid;
@@ -888,7 +886,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
             }
         }
 
-        // Append Search info
+        // Append Search info.
         if (!empty($search)) {
             $headers['filters']['search'] = $search;
             $blogurl->param('search', $search);
@@ -896,7 +894,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         }
     }
 
-    // Append edit mode info
+    // Append edit mode info.
     if (!empty($action) && $action == 'add') {
 
     } else if (!empty($action) && $action == 'edit') {
index 5561050..5df39ad 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -40,7 +39,7 @@ require_once($CFG->libdir . '/filelib.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class blog_entry implements renderable {
-    // Public Database fields
+    // Public Database fields.
     public $id;
     public $userid;
     public $subject;
@@ -49,7 +48,7 @@ class blog_entry implements renderable {
     public $attachment;
     public $publishstate;
 
-    // Locked Database fields (Don't touch these)
+    // Locked Database fields (Don't touch these).
     public $courseid = 0;
     public $groupid = 0;
     public $module = 'blog';
@@ -62,14 +61,13 @@ class blog_entry implements renderable {
     public $created;
     public $usermodified;
 
-    // Other class variables
+    // Other class variables.
     public $form;
     public $tags = array();
 
     /** @var StdClass Data needed to render the entry */
     public $renderable;
 
-    // Methods
     /**
      * Constructor. If given an id, will fetch the corresponding record from the DB.
      *
@@ -137,11 +135,12 @@ class blog_entry implements renderable {
             if ($externalblog = $DB->get_record('blog_external', array('id' => $this->content))) {
                 $urlparts = parse_url($externalblog->url);
                 $this->renderable->externalblogtext = get_string('retrievedfrom', 'blog') . get_string('labelsep', 'langconfig');
-                $this->renderable->externalblogtext .= html_writer::link($urlparts['scheme'] . '://'.$urlparts['host'], $externalblog->name);
+                $this->renderable->externalblogtext .= html_writer::link($urlparts['scheme'] . '://' . $urlparts['host'],
+                                                                         $externalblog->name);
             }
         }
 
-        // Retrieve associations
+        // Retrieve associations.
         $this->renderable->unassociatedentry = false;
         if (!empty($CFG->useblogassociations)) {
 
@@ -165,9 +164,11 @@ class blog_entry implements renderable {
 
                     // Course associations.
                     if ($context->contextlevel ==  CONTEXT_COURSE) {
-                        $instancename = $DB->get_field('course', 'shortname', array('id' => $context->instanceid)); //TODO: performance!!!!
+                        // TODO: performance!!!!
+                        $instancename = $DB->get_field('course', 'shortname', array('id' => $context->instanceid));
 
-                        $associations[$key]->url = $assocurl = new moodle_url('/course/view.php', array('id' => $context->instanceid));
+                        $associations[$key]->url = $assocurl = new moodle_url('/course/view.php',
+                                                                              array('id' => $context->instanceid));
                         $associations[$key]->text = $instancename;
                         $associations[$key]->icon = new pix_icon('i/course', $associations[$key]->text);
                     }
@@ -175,15 +176,17 @@ class blog_entry implements renderable {
                     // Mod associations.
                     if ($context->contextlevel ==  CONTEXT_MODULE) {
 
-                        // Getting the activity type and the activity instance id
+                        // Getting the activity type and the activity instance id.
                         $sql = 'SELECT cm.instance, m.name FROM {course_modules} cm
                                   JOIN {modules} m ON m.id = cm.module
                                  WHERE cm.id = :cmid';
                         $modinfo = $DB->get_record_sql($sql, array('cmid' => $context->instanceid));
-                        $instancename = $DB->get_field($modinfo->name, 'name', array('id' => $modinfo->instance)); //TODO: performance!!!!
+                        // TODO: performance!!!!
+                        $instancename = $DB->get_field($modinfo->name, 'name', array('id' => $modinfo->instance));
 
                         $associations[$key]->type = get_string('modulename', $modinfo->name);
-                        $associations[$key]->url = new moodle_url('/mod/' . $modinfo->name . '/view.php', array('id' => $context->instanceid));
+                        $associations[$key]->url = new moodle_url('/mod/' . $modinfo->name . '/view.php',
+                                                                  array('id' => $context->instanceid));
                         $associations[$key]->text = $instancename;
                         $associations[$key]->icon = new pix_icon('icon', $associations[$key]->text, $modinfo->name);
                     }
@@ -203,7 +206,7 @@ class blog_entry implements renderable {
      * Gets the entry attachments list
      * @return array List of blog_entry_attachment instances
      */
-    function get_attachments() {
+    public function get_attachments() {
 
         global $CFG;
 
@@ -293,7 +296,13 @@ class blog_entry implements renderable {
         }
 
         $entry = file_postupdate_standard_editor($entry, 'summary', $summaryoptions, $sitecontext, 'blog', 'post', $entry->id);
-        $entry = file_postupdate_standard_filemanager($entry, 'attachment', $attachmentoptions, $sitecontext, 'blog', 'attachment', $entry->id);
+        $entry = file_postupdate_standard_filemanager($entry,
+                                                      'attachment',
+                                                      $attachmentoptions,
+                                                      $sitecontext,
+                                                      'blog',
+                                                      'attachment',
+                                                      $entry->id);
 
         if (!empty($CFG->useblogassociations)) {
             $entry->add_associations();
@@ -427,7 +436,7 @@ class blog_entry implements renderable {
 
         if ($otags = optional_param('otags', '', PARAM_INT)) {
             foreach ($otags as $tagid) {
-                // TODO : make this use the tag name in the form
+                // TODO : make this use the tag name in the form.
                 if ($tag = tag_get('id', $tagid)) {
                     $tags[] = $tag->name;
                 }
@@ -456,11 +465,11 @@ class blog_entry implements renderable {
         $sitecontext = context_system::instance();
 
         if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-            return true; // can edit any blog entry
+            return true; // Can edit any blog entry.
         }
 
         if ($this->userid == $userid && has_capability('moodle/blog:create', $sitecontext)) {
-            return true; // can edit own when having blog:create capability
+            return true; // Can edit own when having blog:create capability.
         }
 
         return false;
@@ -480,23 +489,23 @@ class blog_entry implements renderable {
         $sitecontext = context_system::instance();
 
         if (empty($CFG->enableblogs) || !has_capability('moodle/blog:view', $sitecontext)) {
-            return false; // blog system disabled or user has no blog view capability
+            return false; // Blog system disabled or user has no blog view capability.
         }
 
         if (isloggedin() && $USER->id == $targetuserid) {
-            return true; // can view own entries in any case
+            return true; // Can view own entries in any case.
         }
 
         if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-            return true; // can manage all entries
+            return true; // Can manage all entries.
         }
 
-        // coming for 1 entry, make sure it's not a draft
+        // Coming for 1 entry, make sure it's not a draft.
         if ($this->publishstate == 'draft' && !has_capability('moodle/blog:viewdrafts', $sitecontext)) {
-            return false;  // can not view draft of others
+            return false;  // Can not view draft of others.
         }
 
-        // coming for 1 entry, make sure user is logged in, if not a public blog
+        // Coming for 1 entry, make sure user is logged in, if not a public blog.
         if ($this->publishstate != 'public' && !isloggedin()) {
             return false;
         }
@@ -507,7 +516,7 @@ class blog_entry implements renderable {
                 break;
 
             case BLOG_SITE_LEVEL:
-                if (isloggedin()) { // not logged in viewers forbidden
+                if (isloggedin()) { // Not logged in viewers forbidden.
                     return true;
                 }
                 return false;
@@ -533,7 +542,7 @@ class blog_entry implements renderable {
         global $CFG;
         $options = array();
 
-        // everyone gets draft access
+        // Everyone gets draft access.
         if ($CFG->bloglevel >= BLOG_USER_LEVEL) {
             $options['draft'] = get_string('publishtonoone', 'blog');
         }
@@ -577,7 +586,7 @@ class blog_listing {
      * @param array $filters An associative array of filtername => filterid
      */
     public function __construct($filters=array()) {
-        // Unset filters overridden by more specific filters
+        // Unset filters overridden by more specific filters.
         foreach ($filters as $type => $id) {
             if (!empty($type) && !empty($id)) {
                 $this->filters[$type] = blog_filter::get_instance($id, $type);
@@ -615,50 +624,53 @@ class blog_listing {
     public function get_entry_fetch_sql($count=false, $sort='lastmodified DESC', $userid = false) {
         global $DB, $USER, $CFG;
 
-        if(!$userid) {
+        if (!$userid) {
             $userid = $USER->id;
         }
 
         $allnamefields = get_all_user_name_fields(true, 'u');
         // The query used to locate blog entries is complicated.  It will be built from the following components:
-        $requiredfields = "p.*, $allnamefields, u.email";  // the SELECT clause
-        $tables = array('p' => 'post', 'u' => 'user');   // components of the FROM clause (table_id => table_name)
-        $conditions = array('u.deleted = 0', 'p.userid = u.id', '(p.module = \'blog\' OR p.module = \'blog_external\')');  // components of the WHERE clause (conjunction)
+        $requiredfields = "p.*, $allnamefields, u.email";  // The SELECT clause.
+        $tables = array('p' => 'post', 'u' => 'user');   // Components of the FROM clause (table_id => table_name).
+        // Components of the WHERE clause (conjunction).
+        $conditions = array('u.deleted = 0', 'p.userid = u.id', '(p.module = \'blog\' OR p.module = \'blog_external\')');
 
-        // build up a clause for permission constraints
+        // Build up a clause for permission constraints.
 
         $params = array();
 
-        // fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs
-        // admins can see all blogs regardless of publish states, as described on the help page
+        // Fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs.
+        // Admins can see all blogs regardless of publish states, as described on the help page.
         if (has_capability('moodle/user:readuserblogs', context_system::instance())) {
-            // don't add permission constraints
+            // Don't add permission constraints.
 
-        } else if(!empty($this->filters['user']) && has_capability('moodle/user:readuserblogs',
-                context_user::instance((empty($this->filters['user']->id) ? 0 : $this->filters['user']->id)))) {
-            // don't add permission constraints
+        } else if (!empty($this->filters['user'])
+                   && has_capability('moodle/user:readuserblogs',
+                                     context_user::instance((empty($this->filters['user']->id) ? 0 : $this->filters['user']->id)))) {
+            // Don't add permission constraints.
 
         } else {
             if (isloggedin() and !isguestuser()) {
-                $assocexists = $DB->record_exists('blog_association', array());  //dont check association records if there aren't any
+                // Dont check association records if there aren't any.
+                $assocexists = $DB->record_exists('blog_association', array());
 
-                //begin permission sql clause
+                // Begin permission sql clause.
                 $permissionsql =  '(p.userid = ? ';
                 $params[] = $userid;
 
-                if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { // add permission to view site-level entries
+                if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { // Add permission to view site-level entries.
                     $permissionsql .= " OR p.publishstate = 'site' ";
                 }
 
-                if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) { // add permission to view global entries
+                if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) { // Add permission to view global entries.
                     $permissionsql .= " OR p.publishstate = 'public' ";
                 }
 
-                $permissionsql .= ') ';   //close permissions sql clause
-            } else {  // default is access to public entries
+                $permissionsql .= ') ';   // Close permissions sql clause.
+            } else {  // Default is access to public entries.
                 $permissionsql = "p.publishstate = 'public'";
             }
-            $conditions[] = $permissionsql;  //add permission constraints
+            $conditions[] = $permissionsql;  // Add permission constraints.
         }
 
         foreach ($this->filters as $type => $blogfilter) {
@@ -667,7 +679,7 @@ class blog_listing {
             $tables = array_merge($tables, $blogfilter->tables);
         }
 
-        $tablessql = '';  // build up the FROM clause
+        $tablessql = '';  // Build up the FROM clause.
         foreach ($tables as $tablename => $table) {
             $tablessql .= ($tablessql ? ', ' : '').'{'.$table.'} '.$tablename;
         }
@@ -688,7 +700,7 @@ class blog_listing {
         global $CFG, $USER, $DB, $OUTPUT, $PAGE;
         $sitecontext = context_system::instance();
 
-        // Blog renderer
+        // Blog renderer.
         $output = $PAGE->get_renderer('blog');
 
         $page  = optional_param('blogpage', 0, PARAM_INT);
@@ -711,7 +723,7 @@ class blog_listing {
         echo $OUTPUT->render($pagingbar);
 
         if (has_capability('moodle/blog:create', $sitecontext)) {
-            //the user's blog is enabled and they are viewing their own blog
+            // The user's blog is enabled and they are viewing their own blog.
             $userid = optional_param('userid', null, PARAM_INT);
 
             if (empty($userid) || (!empty($userid) && $userid == $USER->id)) {
@@ -744,7 +756,7 @@ class blog_listing {
             foreach ($entries as $entry) {
                 $blogentry = new blog_entry(null, $entry);
 
-                // Get the required blog entry data to render it
+                // Get the required blog entry data to render it.
                 $blogentry->prepare_render();
                 echo $output->render($blogentry);
 
@@ -762,7 +774,7 @@ class blog_listing {
         }
     }
 
-    /// Find the base url from $_GET variables, for print_paging_bar
+    // Find the base url from $_GET variables, for print_paging_bar.
     public function get_baseurl() {
         $getcopy  = $_GET;
 
@@ -897,11 +909,13 @@ class blog_filter_context extends blog_filter {
             $this->type = $type;
         }
 
-        $this->availabletypes = array('site' => get_string('site'), 'course' => get_string('course'), 'module' => get_string('activity'));
+        $this->availabletypes = array('site' => get_string('site'),
+                                      'course' => get_string('course'),
+                                      'module' => get_string('activity'));
 
         switch ($this->type) {
             case 'course': // Careful of site course!
-                // Ignore course filter if blog associations are not enabled
+                // Ignore course filter if blog associations are not enabled.
                 if ($this->id != $SITE->id && !empty($CFG->useblogassociations)) {
                     $this->overrides = array('site');
                     $context = context_course::instance($this->id);
@@ -910,11 +924,11 @@ class blog_filter_context extends blog_filter {
                     $this->conditions[] = 'ba.contextid = '.$context->id;
                     break;
                 } else {
-                    // We are dealing with the site course, do not break from the current case
+                    // We are dealing with the site course, do not break from the current case.
                 }
 
             case 'site':
-                // No special constraints
+                // No special constraints.
                 break;
             case 'module':
                 if (!empty($CFG->useblogassociations)) {
@@ -961,7 +975,7 @@ class blog_filter_user extends blog_filter {
             $this->params = array($this->id);
             $this->overrides = array('group');
 
-        } elseif ($this->type == 'group') {
+        } else if ($this->type == 'group') {
             $this->overrides = array('course', 'site');
 
             $this->tables['gm'] = 'groups_members';
@@ -969,7 +983,7 @@ class blog_filter_user extends blog_filter {
             $this->conditions[] = 'gm.groupid = ?';
             $this->params[]     = $this->id;
 
-            if (!empty($CFG->useblogassociations)) {  // only show blog entries associated with this course
+            if (!empty($CFG->useblogassociations)) {  // Only show blog entries associated with this course.
                 $coursecontext     = context_course::instance($DB->get_field('groups', 'courseid', array('id' => $this->id)));
                 $this->tables['ba'] = 'blog_association';
                 $this->conditions[] = 'gm.groupid = ?';
@@ -1068,7 +1082,8 @@ class blog_entry_attachment implements renderable {
 
         $this->file = $file;
         $this->filename = $file->get_filename();
-        $this->url = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.SYSCONTEXTID.'/blog/attachment/'.$entryid.'/'.$this->filename);
+        $this->url = file_encode_url($CFG->wwwroot . '/pluginfile.php',
+                                     '/' . SYSCONTEXTID . '/blog/attachment/' . $entryid . '/' . $this->filename);
     }
 
 }
index e3d82fc..59aea44 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -66,7 +65,7 @@ if (empty($CFG->enableblogs)) {
 // The preference is site wide not blog specific. Hence user should have permissions in site level.
 require_capability('moodle/blog:view', $sitecontext);
 
-/// If data submitted, then process and store.
+// If data submitted, then process and store.
 
 $mform = new blog_preferences_form('preferences.php');
 $mform->set_data(array('pagesize' => get_user_preferences('blogpagesize')));
@@ -80,7 +79,7 @@ if (!$mform->is_cancelled() && $data = $mform->get_data()) {
     set_user_preference('blogpagesize', $pagesize);
 }
 
-if ($mform->is_cancelled()){
+if ($mform->is_cancelled()) {
     redirect($CFG->wwwroot . '/blog/index.php');
 }
 
index d5c5005..12edfed 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -26,7 +25,7 @@
  */
 
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');    //  It must be included from a Moodle page.
 }
 
 require_once($CFG->libdir.'/formslib.php');
index af1724d..832d4b1 100644 (file)
@@ -63,7 +63,9 @@ class core_blog_renderer extends plugin_renderer_base {
         $o .= $this->output->container_start('topic starter header clearfix');
 
         // Title.
-        $titlelink =  html_writer::link(new moodle_url('/blog/index.php', array('entryid' => $entry->id)), format_string($entry->subject));
+        $titlelink = html_writer::link(new moodle_url('/blog/index.php',
+                                                       array('entryid' => $entry->id)),
+                                                       format_string($entry->subject));
         $o .= $this->output->container($titlelink, 'subject');
 
         // Post by.
@@ -244,9 +246,14 @@ class core_blog_renderer extends plugin_renderer_base {
             $o = html_writer::empty_tag('img', $attrs);
             $class = 'attachedimages';
         } else {
-            $image = $this->output->pix_icon(file_file_icon($attachment->file), $attachment->filename, 'moodle', array('class'=>'icon'));
+            $image = $this->output->pix_icon(file_file_icon($attachment->file),
+                                             $attachment->filename,
+                                             'moodle',
+                                             array('class' => 'icon'));
             $o = html_writer::link($attachment->url, $image);
-            $o .= format_text(html_writer::link($attachment->url, $attachment->filename), FORMAT_HTML, array('context' => $syscontext));
+            $o .= format_text(html_writer::link($attachment->url, $attachment->filename),
+                              FORMAT_HTML,
+                              array('context' => $syscontext));
             $class = 'attachments';
         }
 
index 12854d6..3f26eb0 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -97,9 +96,6 @@ function blog_rss_print_link($context, $filtertype, $filterselect=0, $tagid=0, $
 function blog_rss_add_http_header($context, $title, $filtertype, $filterselect=0, $tagid=0) {
     global $PAGE, $USER, $CFG;
 
-    //$componentname = 'blog';
-    //rss_add_http_header($context, $componentname, $filterselect, $title);
-
     if (!isloggedin()) {
         $userid = $CFG->siteguest;
     } else {
@@ -159,7 +155,7 @@ function blog_rss_get_feed($context, $args) {
 
     if ($CFG->bloglevel == BLOG_SITE_LEVEL) {
         if (isguestuser()) {
-            debugging(get_string('nopermissiontoshow','error'));
+            debugging(get_string('nopermissiontoshow', 'error'));
             return '';
         }
     }
@@ -170,7 +166,7 @@ function blog_rss_get_feed($context, $args) {
     }
 
     $type  = clean_param($args[3], PARAM_ALPHA);
-    $id = clean_param($args[4], PARAM_INT);  // could be groupid / courseid  / userid  depending on $type
+    $id = clean_param($args[4], PARAM_INT);  // Could be groupid / courseid  / userid  depending on $type.
 
     $tagid=0;
     if ($args[5] != 'rss.xml') {
@@ -183,14 +179,13 @@ function blog_rss_get_feed($context, $args) {
 
     if (file_exists($filename)) {
         if (filemtime($filename) + 3600 > time()) {
-            return $filename;   // It's already done so we return cached version
+            return $filename;   // It's already done so we return cached version.
         }
     }
 
     $courseid = $groupid = $userid = null;
     switch ($type) {
         case 'site':
-            //$siteid = $id;
             break;
         case 'course':
             $courseid = $id;
@@ -203,26 +198,26 @@ function blog_rss_get_feed($context, $args) {
             break;
     }
 
-    // Get all the entries from the database
+    // Get all the entries from the database.
     require_once($CFG->dirroot .'/blog/locallib.php');
     $blogheaders = blog_get_headers($courseid, $groupid, $userid, $tagid);
 
     $bloglisting = new blog_listing($blogheaders['filters']);
     $blogentries = $bloglisting->get_entries();
 
-    // Now generate an array of RSS items
+    // Now generate an array of RSS items.
     if ($blogentries) {
         $items = array();
-        foreach ($blogentries as $blog_entry) {
-            $item = NULL;
-            $item->author = fullname($DB->get_record('user', array('id'=>$blog_entry->userid))); // TODO: this is slow
-            $item->title = $blog_entry->subject;
-            $item->pubdate = $blog_entry->lastmodified;
-            $item->link = $CFG->wwwroot.'/blog/index.php?entryid='.$blog_entry->id;
-            $summary = file_rewrite_pluginfile_urls($blog_entry->summary, 'pluginfile.php',
-                $sitecontext->id, 'blog', 'post', $blog_entry->id);
-            $item->description = format_text($summary, $blog_entry->format);
-            if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blog_entry->id)) ) {
+        foreach ($blogentries as $blogentry) {
+            $item = null;
+            $item->author = fullname($DB->get_record('user', array('id' => $blogentry->userid))); // TODO: this is slow.
+            $item->title = $blogentry->subject;
+            $item->pubdate = $blogentry->lastmodified;
+            $item->link = $CFG->wwwroot.'/blog/index.php?entryid='.$blogentry->id;
+            $summary = file_rewrite_pluginfile_urls($blogentry->summary, 'pluginfile.php',
+                $sitecontext->id, 'blog', 'post', $blogentry->id);
+            $item->description = format_text($summary, $blogentry->format);
+            if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blogentry->id)) ) {
                 if ($blogtags) {
                     $item->tags = $blogtags;
                 }
@@ -230,12 +225,12 @@ function blog_rss_get_feed($context, $args) {
             }
             $items[] = $item;
         }
-        $articles = rss_add_items($items);   /// Change structure to XML
+        $articles = rss_add_items($items);   // Change structure to XML.
     } else {
         $articles = '';
     }
 
-/// Get header and footer information
+    // Get header and footer information.
 
     switch ($type) {
         case 'user':
@@ -250,7 +245,7 @@ function blog_rss_get_feed($context, $args) {
             break;
         case 'group':
             $group = groups_get_group($id);
-            $info = $group->name; //TODO: $DB->get_field('groups', 'name', array('id'=>$id))
+            $info = $group->name; // TODO: $DB->get_field('groups', 'name', array('id'=>$id)).
             break;
         default:
             $info = '';
@@ -261,18 +256,18 @@ function blog_rss_get_feed($context, $args) {
         $info .= ': '.$DB->get_field('tags', 'text', array('id'=>$tagid));
     }
 
-    $header = rss_standard_header(get_string($type.'blog','blog', $info),
+    $header = rss_standard_header(get_string($type.'blog', 'blog', $info),
                                   $CFG->wwwroot.'/blog/index.php',
-                                  get_string('intro','blog'));
+                                  get_string('intro', 'blog'));
 
     $footer = rss_standard_footer();
 
     // Save the XML contents to file.
     $rssdata = $header.$articles.$footer;
-    if (blog_rss_save_file($type,$id,$tagid,$rssdata)) {
+    if (blog_rss_save_file($type, $id, $tagid, $rssdata)) {
         return $filename;
     } else {
-        return false;   // Couldn't find it or make it
+        return false;   // Couldn't find it or make it.
     }
 }
 
@@ -308,12 +303,12 @@ function blog_rss_save_file($type, $id, $tagid=0, $contents='') {
 
     $status = true;
 
-    //blog creates some additional dirs within the rss cache so make sure they all exist
+    // Blog creates some additional dirs within the rss cache so make sure they all exist.
     make_cache_directory('rss/blog');
     make_cache_directory('rss/blog/'.$type);
 
     $filename = blog_rss_file_name($type, $id, $tagid);
-    $expandfilename = false; //we're supplying a full file path
+    $expandfilename = false; // We are supplying a full file path.
     $status = rss_save_file('blog', $filename, $contents, $expandfilename);
 
     return $status;
index 2db2265..06b1f07 100644 (file)
@@ -32,7 +32,7 @@ require_once($CFG->dirroot . '/blog/lib.php');
  */
 class core_bloglib_testcase extends advanced_testcase {
 
-    private $courseid; // To store important ids to be used in tests
+    private $courseid;
     private $cmid;
     private $groupid;
     private $userid;
@@ -45,22 +45,22 @@ class core_bloglib_testcase extends advanced_testcase {
 
         $this->resetAfterTest();
 
-        // Create default course
+        // Create default course.
         $course = $this->getDataGenerator()->create_course(array('category'=>1, 'shortname'=>'ANON'));
         $this->assertNotEmpty($course);
         $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
         $this->assertNotEmpty($page);
 
-        // Create default group
+        // Create default group.
         $group = new stdClass();
         $group->courseid = $course->id;
         $group->name = 'ANON';
         $group->id = $DB->insert_record('groups', $group);
 
-        // Create default user
+        // Create default user.
         $user = $this->getDataGenerator()->create_user(array('username'=>'testuser', 'firstname'=>'Jimmy', 'lastname'=>'Kinnon'));
 
-        // Create default tag
+        // Create default tag.
         $tag = new stdClass();
         $tag->userid = $user->id;
         $tag->name = 'testtagname';
@@ -68,14 +68,14 @@ class core_bloglib_testcase extends advanced_testcase {
         $tag->tagtype = 'official';
         $tag->id = $DB->insert_record('tag', $tag);
 
-        // Create default post
+        // Create default post.
         $post = new stdClass();
         $post->userid = $user->id;
         $post->groupid = $group->id;
         $post->content = 'test post content text';
         $post->id = $DB->insert_record('post', $post);
 
-        // Grab important ids
+        // Grab important ids.
         $this->courseid = $course->id;
         $this->cmid = $page->cmid;
         $this->groupid  = $group->id;
@@ -88,7 +88,7 @@ class core_bloglib_testcase extends advanced_testcase {
     public function test_overrides() {
         global $SITE;
 
-        // Try all the filters at once: Only the entry filter is active
+        // Try all the filters at once: Only the entry filter is active.
         $filters = array('site' => $SITE->id, 'course' => $this->courseid, 'module' => $this->cmid,
             'group' => $this->groupid, 'user' => $this->userid, 'tag' => $this->tagid, 'entry' => $this->postid);
         $blog_listing = new blog_listing($filters);
@@ -100,7 +100,7 @@ class core_bloglib_testcase extends advanced_testcase {
         $this->assertFalse(array_key_exists('tag', $blog_listing->filters));
         $this->assertTrue(array_key_exists('entry', $blog_listing->filters));
 
-        // Again, but without the entry filter: This time, the tag, user and module filters are active
+        // Again, but without the entry filter: This time, the tag, user and module filters are active.
         $filters = array('site' => $SITE->id, 'course' => $this->courseid, 'module' => $this->cmid,
             'group' => $this->groupid, 'user' => $this->userid, 'tag' => $this->postid);
         $blog_listing = new blog_listing($filters);
@@ -111,7 +111,7 @@ class core_bloglib_testcase extends advanced_testcase {
         $this->assertTrue(array_key_exists('user', $blog_listing->filters));
         $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
 
-        // We should get the same result by removing the 3 inactive filters: site, course and group:
+        // We should get the same result by removing the 3 inactive filters: site, course and group.
         $filters = array('module' => $this->cmid, 'user' => $this->userid, 'tag' => $this->tagid);
         $blog_listing = new blog_listing($filters);
         $this->assertFalse(array_key_exists('site', $blog_listing->filters));
@@ -128,26 +128,26 @@ class core_bloglib_testcase extends advanced_testcase {
 
     public function test_blog_get_headers_case_1() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers();
-        $this->assertEquals($blog_headers['heading'], get_string('siteblog', 'blog', 'phpunit'));
+        $blogheaders = blog_get_headers();
+        $this->assertEquals($blogheaders['heading'], get_string('siteblog', 'blog', 'phpunit'));
     }
 
     public function test_blog_get_headers_case_6() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers($this->courseid, NULL, $this->userid);
-        $this->assertNotEquals($blog_headers['heading'], '');
+        $blogheaders = blog_get_headers($this->courseid, null, $this->userid);
+        $this->assertNotEquals($blogheaders['heading'], '');
     }
 
     public function test_blog_get_headers_case_7() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers(NULL, $this->groupid);
-        $this->assertNotEquals($blog_headers['heading'], '');
+        $blogheaders = blog_get_headers(null, $this->groupid);
+        $this->assertNotEquals($blogheaders['heading'], '');
     }
 
     public function test_blog_get_headers_case_10() {
         global $CFG, $PAGE, $OUTPUT;
-        $blog_headers = blog_get_headers($this->courseid);
-        $this->assertNotEquals($blog_headers['heading'], '');
+        $blogheaders = blog_get_headers($this->courseid);
+        $this->assertNotEquals($blogheaders['heading'], '');
     }
 
     /**
index c9c35db..775ce25 100644 (file)
@@ -52,7 +52,7 @@ $locks = cache_administration_helper::get_lock_summaries();
 
 $title = new lang_string('cacheadmin', 'cache');
 $mform = null;
-$notification = null;
+$notifications = array();
 $notifysuccess = true;
 
 if (!empty($action) && confirm_sesskey()) {
@@ -110,10 +110,10 @@ if (!empty($action) && confirm_sesskey()) {
 
             if (!array_key_exists($store, $stores)) {
                 $notifysuccess = false;
-                $notification = get_string('invalidstore', 'cache');
+                $notifications[] = array(get_string('invalidstore', 'cache'), false);
             } else if ($stores[$store]['mappings'] > 0) {
                 $notifysuccess = false;
-                $notification = get_string('deletestorehasmappings', 'cache');
+                $notifications[] = array(get_string('deletestorehasmappings', 'cache'), false);
             }
 
             if ($notifysuccess) {
@@ -250,10 +250,10 @@ if (!empty($action) && confirm_sesskey()) {
             $confirm = optional_param('confirm', false, PARAM_BOOL);
             if (!array_key_exists($lock, $locks)) {
                 $notifysuccess = false;
-                $notification = get_string('invalidlock', 'cache');
+                $notifications[] = array(get_string('invalidlock', 'cache'), false);
             } else if ($locks[$lock]['uses'] > 0) {
                 $notifysuccess = false;
-                $notification = get_string('deletelockhasuses', 'cache');
+                $notifications[] = array(get_string('deletelockhasuses', 'cache'), false);
             }
             if ($notifysuccess) {
                 if (!$confirm) {
@@ -280,6 +280,12 @@ if (!empty($action) && confirm_sesskey()) {
     }
 }
 
+// Add cache store warnings to the list of notifications.
+// Obviously as these are warnings they are show as failures.
+foreach (cache_helper::warnings($stores) as $warning) {
+    $notifications[] = array($warning, false);
+}
+
 $PAGE->set_title($title);
 $PAGE->set_heading($SITE->fullname);
 /* @var core_cache_renderer $renderer */
@@ -287,10 +293,7 @@ $renderer = $PAGE->get_renderer('core_cache');
 
 echo $renderer->header();
 echo $renderer->heading($title);
-
-if (!is_null($notification)) {
-    echo $renderer->notification($notification, ($notifysuccess)?'notifysuccess' : 'notifyproblem');
-}
+echo $renderer->notifications($notifications);
 
 if ($mform instanceof moodleform) {
     $mform->display();
index 02bd243..dd150b7 100644 (file)
@@ -736,4 +736,28 @@ class cache_helper {
         }
         return $stores;
     }
+
+    /**
+     * Returns an array of warnings from the cache API.
+     *
+     * The warning returned here are for things like conflicting store instance configurations etc.
+     * These get shown on the admin notifications page for example.
+     *
+     * @param array|null $stores An array of stores to get warnings for, or null for all.
+     * @return string[]
+     */
+    public static function warnings(array $stores = null) {
+        global $CFG;
+        if ($stores === null) {
+            require_once($CFG->dirroot.'/cache/locallib.php');
+            $stores = cache_administration_helper::get_store_instance_summaries();
+        }
+        $warnings = array();
+        foreach ($stores as $store) {
+            if (!empty($store['warnings'])) {
+                $warnings = array_merge($warnings, $store['warnings']);
+            }
+        }
+        return $warnings;
+    }
 }
index b5cfcc1..9d124d3 100644 (file)
@@ -365,4 +365,16 @@ abstract class cache_store implements cache_store_interface {
     public static function initialise_unit_test_instance(cache_definition $definition) {
         return static::initialise_test_instance($definition);
     }
+
+    /**
+     * Can be overridden to return any warnings this store instance should make to the admin.
+     *
+     * This should be used to notify things like configuration conflicts etc.
+     * The warnings returned here will be displayed on the cache configuration screen.
+     *
+     * @return string[] An array of warning strings from the store instance.
+     */
+    public function get_warnings() {
+        return array();
+    }
 }
index 042b891..58dcdd8 100644 (file)
@@ -709,7 +709,8 @@ abstract class cache_administration_helper extends cache_helper {
                     'nativelocking' => ($store instanceof cache_is_lockable),
                     'keyawareness' => ($store instanceof cache_is_key_aware),
                     'searchable' => ($store instanceof cache_is_searchable)
-                )
+                ),
+                'warnings' => $store->get_warnings()
             );
             if (empty($details['default'])) {
                 $return[$name] = $record;
index 685b838..1ccb4bb 100644 (file)
@@ -235,6 +235,8 @@ class core_cache_renderer extends plugin_renderer_base {
         );
         $table->data = array();
 
+        core_collator::asort_array_of_arrays_by_key($definitions, 'name');
+
         $none = new lang_string('none', 'cache');
         foreach ($definitions as $id => $definition) {
             $actions = cache_administration_helper::get_definition_actions($context, $definition);
@@ -372,4 +374,30 @@ class core_cache_renderer extends plugin_renderer_base {
         $html .= html_writer::end_tag('div');
         return $html;
     }
+
+    /**
+     * Renders an array of notifications for the cache configuration screen.
+     *
+     * Takes an array of notifications with the form:
+     * $notifications = array(
+     *     array('This is a success message', true),
+     *     array('This is a failure message', false),
+     * );
+     *
+     * @param array $notifications
+     * @return string
+     */
+    public function notifications(array $notifications = array()) {
+        if (count($notifications) === 0) {
+            // There are no notifications to render.
+            return '';
+        }
+        $html = html_writer::start_div('notifications');
+        foreach ($notifications as $notification) {
+            list($message, $notifysuccess) = $notification;
+            $html .= $this->notification($message, ($notifysuccess) ? 'notifysuccess' : 'notifyproblem');
+        }
+        $html .= html_writer::end_div();
+        return $html;
+    }
 }
\ No newline at end of file
index 78d3947..26f1c9e 100644 (file)
@@ -64,6 +64,7 @@ For example:
 server.url.com
 ipaddress:port
 </pre>';
+$string['sessionhandlerconflict'] = 'Warning: A memcache instance ({$a}) has being configured to use the same memcached server as sessions. Purging all caches will lead to sessions also being purged.';
 $string['testservers'] = 'Test servers';
 $string['testservers_desc'] = 'The test servers get used for unit tests and for performance tests. It is entirely optional to set up test servers. Servers should be defined one per line and consist of a server address and optionally a port and weight.
 If no port is provided then the default port (11211) is used.';
\ No newline at end of file
index 3a7da5f..aa5c15d 100644 (file)
@@ -573,4 +573,28 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
     public function my_name() {
         return $this->name;
     }
+
+    /**
+     * Used to notify of configuration conflicts.
+     *
+     * The warnings returned here will be displayed on the cache configuration screen.
+     *
+     * @return string[] Returns an array of warnings (strings)
+     */
+    public function get_warnings() {
+        global $CFG;
+        $warnings = array();
+        if (isset($CFG->session_memcached_save_path) && count($this->servers)) {
+            $bits = explode(':', $CFG->session_memcached_save_path, 3);
+            $host = array_shift($bits);
+            $port = (count($bits)) ? array_shift($bits) : '11211';
+            foreach ($this->servers as $server) {
+                if ($server[0] === $host && $server[1] == $port) {
+                    $warnings[] = get_string('sessionhandlerconflict', 'cachestore_memcache', $this->my_name());
+                    break;
+                }
+            }
+        }
+        return $warnings;
+    }
 }
index 5d35c1c..97fe5b6 100644 (file)
@@ -78,6 +78,7 @@ For example:
 server.url.com
 ipaddress:port
 </pre>';
+$string['sessionhandlerconflict'] = 'Warning: A memcached instance ({$a}) has being configured to use the same memcached server as sessions. Purging all caches will lead to sessions also being purged.';
 $string['testservers'] = 'Test servers';
 $string['testservers_desc'] = 'The test servers get used for unit tests and for performance tests. It is entirely optional to set up test servers. Servers should be defined one per line and consist of a server address and optionally a port and weight.
 If no port is provided then the default port (11211) is used.';
index 284f3c8..b379b26 100644 (file)
@@ -668,4 +668,29 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
     public function my_name() {
         return $this->name;
     }
+
+    /**
+     * Used to notify of configuration conflicts.
+     *
+     * The warnings returned here will be displayed on the cache configuration screen.
+     *
+     * @return string[] Returns an array of warnings (strings)
+     */
+    public function get_warnings() {
+        global $CFG;
+        $warnings = array();
+        if (isset($CFG->session_memcached_save_path) && count($this->servers)) {
+            $bits = explode(':', $CFG->session_memcached_save_path, 3);
+            $host = array_shift($bits);
+            $port = (count($bits)) ? array_shift($bits) : '11211';
+
+            foreach ($this->servers as $server) {
+                if ((string)$server[0] === $host && (string)$server[1] === $port) {
+                    $warnings[] = get_string('sessionhandlerconflict', 'cachestore_memcached', $this->my_name());
+                    break;
+                }
+            }
+        }
+        return $warnings;
+    }
 }
index 69a8924..6a1bdf9 100644 (file)
@@ -120,7 +120,7 @@ class event_form extends moodleform {
         $group[] =& $mform->createElement('radio', 'duration', null, get_string('durationuntil', 'calendar'), 1);
         $group[] =& $mform->createElement('date_time_selector', 'timedurationuntil', '');
         $group[] =& $mform->createElement('radio', 'duration', null, get_string('durationminutes', 'calendar'), 2);
-        $group[] =& $mform->createElement('text', 'timedurationminutes', null);
+        $group[] =& $mform->createElement('text', 'timedurationminutes', get_string('durationminutes', 'calendar'));
 
         $mform->addGroup($group, 'durationgroup', '', '<br />', false);
 
index c3304fa..dcedc54 100644 (file)
@@ -3201,10 +3201,10 @@ function calendar_cron() {
         mtrace("Updating calendar subscription {$sub->name} in course {$sub->courseid}");
         try {
             $log = calendar_update_subscription_events($sub->id);
+            mtrace(trim(strip_tags($log)));
         } catch (moodle_exception $ex) {
-
+            mtrace('Error updating calendar subscription: ' . $ex->getMessage());
         }
-        mtrace(trim(strip_tags($log)));
     }
 
     mtrace('Finished updating calendar subscriptions.');
index c405b96..2a61b5e 100644 (file)
@@ -35,9 +35,11 @@ require_once($CFG->dirroot . '/calendar/lib.php');
  */
 class core_calendar_lib_testcase extends advanced_testcase {
 
-    public function test_calendar_get_course_cached() {
+    protected function setUp() {
         $this->resetAfterTest(true);
+    }
 
+    public function test_calendar_get_course_cached() {
         // Setup some test courses.
         $course1 = $this->getDataGenerator()->create_course();
         $course2 = $this->getDataGenerator()->create_course();
@@ -68,4 +70,50 @@ class core_calendar_lib_testcase extends advanced_testcase {
         $this->assertEquals($course3->shortname, $cachedcourse3->shortname);
         $this->assertEquals($course3->fullname, $cachedcourse3->fullname);
     }
+
+    /**
+     * Test calendar cron with a working subscription URL.
+     */
+    public function test_calendar_cron_working_url() {
+        global $CFG;
+        require_once($CFG->dirroot . '/lib/cronlib.php');
+
+        // Moodle ICal URL (moodle.org events).
+        $presetwhat = 'all';
+        $presettime = 'recentupcoming';
+        $userid = 1;
+        $authtoken = 'a8bcfee2fb868a05357f650bd65dc0699b026524';
+        $subscriptionurl = 'https://moodle.org/calendar/export_execute.php'
+                . '?preset_what='.$presetwhat.'&preset_time='.$presettime.'&userid='.$userid.'&authtoken='.$authtoken;
+
+        $subscription = new stdClass();
+        $subscription->eventtype = 'site';
+        $subscription->name = 'test';
+        $subscription->url = $subscriptionurl;
+        $subscription->pollinterval = 86400;
+        $subscription->lastupdated = 0;
+        calendar_add_subscription($subscription);
+
+        $this->expectOutputRegex('/Events imported: .* Events updated:/');
+        calendar_cron();
+    }
+
+    /**
+     * Test calendar cron with a broken subscription URL.
+     */
+    public function test_calendar_cron_broken_url() {
+        global $CFG;
+        require_once($CFG->dirroot . '/lib/cronlib.php');
+
+        $subscription = new stdClass();
+        $subscription->eventtype = 'site';
+        $subscription->name = 'test';
+        $subscription->url = 'brokenurl';
+        $subscription->pollinterval = 86400;
+        $subscription->lastupdated = 0;
+        calendar_add_subscription($subscription);
+
+        $this->expectOutputRegex('/Error updating calendar subscription: The given iCal URL is invalid/');
+        calendar_cron();
+    }
 }
index 9a02d19..14de49b 100644 (file)
@@ -221,12 +221,22 @@ class helper {
             $actions['resortbyname'] = array(
                 'url' => new \moodle_url($baseurl, array('action' => 'resortcategories', 'resort' => 'name')),
                 'icon' => new \pix_icon('t/sort', new \lang_string('sort')),
-                'string' => new \lang_string('resortsubcategoriesbyname', 'moodle')
+                'string' => new \lang_string('resortsubcategoriesby', 'moodle' , get_string('categoryname'))
+            );
+            $actions['resortbynamedesc'] = array(
+                'url' => new \moodle_url($baseurl, array('action' => 'resortcategories', 'resort' => 'namedesc')),
+                'icon' => new \pix_icon('t/sort', new \lang_string('sort')),
+                'string' => new \lang_string('resortsubcategoriesbyreverse', 'moodle', get_string('categoryname'))
             );
             $actions['resortbyidnumber'] = array(
                 'url' => new \moodle_url($baseurl, array('action' => 'resortcategories', 'resort' => 'idnumber')),
                 'icon' => new \pix_icon('t/sort', new \lang_string('sort')),
-                'string' => new \lang_string('resortsubcategoriesbyidnumber', 'moodle')
+                'string' => new \lang_string('resortsubcategoriesby', 'moodle', get_string('idnumbercoursecategory'))
+            );
+            $actions['resortbyidnumberdesc'] = array(
+                'url' => new \moodle_url($baseurl, array('action' => 'resortcategories', 'resort' => 'idnumberdesc')),
+                'icon' => new \pix_icon('t/sort', new \lang_string('sort')),
+                'string' => new \lang_string('resortsubcategoriesbyreverse', 'moodle', get_string('idnumbercoursecategory'))
             );
         }
 
index 688e304..6ed18dd 100644 (file)
@@ -407,8 +407,10 @@ class core_course_management_renderer extends plugin_renderer_base {
             $form .= html_writer::div(
                 html_writer::select(
                     array(
-                        'name' => get_string('sortcategoriesbyname'),
-                        'idnumber' => get_string('sortcategoriesbyidnumber'),
+                        'name' => get_string('sortbyx', 'moodle', get_string('categoryname')),
+                        'namedesc' => get_string('sortbyxreverse', 'moodle', get_string('categoryname')),
+                        'idnumber' => get_string('sortbyx', 'moodle', get_string('idnumbercoursecategory')),
+                        'idnumberdesc' => get_string('sortbyxreverse' , 'moodle' , get_string('idnumbercoursecategory')),
                         'none' => get_string('dontsortcategories')
                     ),
                     'resortcategoriesby',
@@ -420,9 +422,14 @@ class core_course_management_renderer extends plugin_renderer_base {
             $form .= html_writer::div(
                 html_writer::select(
                     array(
-                        'fullname' => get_string('sortcoursesbyfullname'),
-                        'shortname' => get_string('sortcoursesbyshortname'),
-                        'idnumber' => get_string('sortcoursesbyidnumber'),
+                        'fullname' => get_string('sortbyx', 'moodle', get_string('fullnamecourse')),
+                        'fullnamedesc' => get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse')),
+                        'shortname' => get_string('sortbyx', 'moodle', get_string('shortnamecourse')),
+                        'shortnamedesc' => get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse')),
+                        'idnumber' => get_string('sortbyx', 'moodle', get_string('idnumbercourse')),
+                        'idnumberdesc' => get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse')),
+                        'timecreated' => get_string('sortbyx', 'moodle', get_string('timecreatedcourse')),
+                        'timecreateddesc' => get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')),
                         'none' => get_string('dontsortcourses')
                     ),
                     'resortcoursesby',
@@ -676,12 +683,38 @@ class core_course_management_renderer extends plugin_renderer_base {
             $params['sesskey'] = sesskey();
             $baseurl = new moodle_url('/course/management.php', $params);
             $fullnameurl = new moodle_url($baseurl, array('resort' => 'fullname'));
+            $fullnameurldesc = new moodle_url($baseurl, array('resort' => 'fullnamedesc'));
             $shortnameurl = new moodle_url($baseurl, array('resort' => 'shortname'));
+            $shortnameurldesc = new moodle_url($baseurl, array('resort' => 'shortnamedesc'));
             $idnumberurl = new moodle_url($baseurl, array('resort' => 'idnumber'));
+            $idnumberdescurl = new moodle_url($baseurl, array('resort' => 'idnumberdesc'));
+            $timecreatedurl = new moodle_url($baseurl, array('resort' => 'timecreated'));
+            $timecreateddescurl = new moodle_url($baseurl, array('resort' => 'timecreateddesc'));
             $menu = new action_menu(array(
-                new action_menu_link_secondary($fullnameurl, null, get_string('resortbyfullname')),
-                new action_menu_link_secondary($shortnameurl, null, get_string('resortbyshortname')),
-                new action_menu_link_secondary($idnumberurl, null, get_string('resortbyidnumber'))
+                new action_menu_link_secondary($fullnameurl,
+                                               null,
+                                               get_string('sortbyx', 'moodle', get_string('fullnamecourse'))),
+                new action_menu_link_secondary($fullnameurldesc,
+                                               null,
+                                               get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse'))),
+                new action_menu_link_secondary($shortnameurl,
+                                               null,
+                                               get_string('sortbyx', 'moodle', get_string('shortnamecourse'))),
+                new action_menu_link_secondary($shortnameurldesc,
+                                               null,
+                                               get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse'))),
+                new action_menu_link_secondary($idnumberurl,
+                                               null,
+                                               get_string('sortbyx', 'moodle', get_string('idnumbercourse'))),
+                new action_menu_link_secondary($idnumberdescurl,
+                                               null,
+                                               get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse'))),
+                new action_menu_link_secondary($timecreatedurl,
+                                               null,
+                                               get_string('sortbyx', 'moodle', get_string('timecreatedcourse'))),
+                new action_menu_link_secondary($timecreateddescurl,
+                                               null,
+                                               get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')))
             ));
             $menu->set_menu_trigger(get_string('resortcourses'));
             $actions[] = $this->render($menu);
@@ -1203,6 +1236,51 @@ class core_course_management_renderer extends plugin_renderer_base {
         return html_writer::span(join('', $actions), 'course-item-actions item-actions');
     }
 
+    /**
+     * Renders html to display a course search form
+     *
+     * @param string $value default value to populate the search field
+     * @param string $format display format - 'plain' (default), 'short' or 'navbar'
+     * @return string
+     */
+    public function course_search_form($value = '', $format = 'plain') {
+        static $count = 0;
+        $formid = 'coursesearch';
+        if ((++$count) > 1) {
+            $formid .= $count;
+        }
+
+        switch ($format) {
+            case 'navbar' :
+                $formid = 'coursesearchnavbar';
+                $inputid = 'navsearchbox';
+                $inputsize = 20;
+                break;
+            case 'short' :
+                $inputid = 'shortsearchbox';
+                $inputsize = 12;
+                break;
+            default :
+                $inputid = 'coursesearchbox';
+                $inputsize = 30;
+        }
+
+        $strsearchcourses = get_string("searchcourses");
+        $searchurl = new moodle_url('/course/management.php');
+
+        $output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get'));
+        $output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset'));
+        $output .= html_writer::tag('label', $strsearchcourses.': ', array('for' => $inputid));
+        $output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid,
+            'size' => $inputsize, 'name' => 'search', 'value' => s($value)));
+        $output .= html_writer::empty_tag('input', array('type' => 'submit',
+            'value' => get_string('go')));
+        $output .= html_writer::end_tag('fieldset');
+        $output .= html_writer::end_tag('form');
+
+        return $output;
+    }
+
     /**
      * Creates access hidden skip to links for the displayed sections.
      *
index ffde87b..1915299 100644 (file)
@@ -2517,7 +2517,8 @@ function create_course($data, $editoroptions = NULL) {
         }
     }
 
-    $data->timecreated  = time();
+    // Check if timecreated is given.
+    $data->timecreated  = !empty($data->timecreated) ? $data->timecreated : time();
     $data->timemodified = $data->timecreated;
 
     // place at beginning of any category
index c48158d..85a2494 100644 (file)
@@ -354,10 +354,14 @@ if ($action !== false && confirm_sesskey()) {
                     // They're not sorting anything.
                     break;
                 }
-                if (!in_array($sortcategoriesby, array('idnumber', 'name'))) {
+                if (!in_array($sortcategoriesby, array('idnumber', 'idnumberdesc',
+                                                       'name', 'namedesc'))) {
                     $sortcategoriesby = false;
                 }
-                if (!in_array($sortcoursesby, array('idnumber', 'fullname', 'shortname'))) {
+                if (!in_array($sortcoursesby, array('timecreated', 'timecreateddesc',
+                                                    'idnumber', 'idnumberdesc',
+                                                    'fullname', 'fullnamedesc',
+                                                    'shortname', 'shortnamedesc'))) {
                     $sortcoursesby = false;
                 }
 
@@ -508,4 +512,6 @@ echo $renderer->grid_end();
 
 // End of the management form.
 echo $renderer->management_form_end();
+echo $renderer->course_search_form($search);
+
 echo $renderer->footer();
index 96f7359..55d242f 100644 (file)
@@ -1098,8 +1098,9 @@ class core_course_renderer extends plugin_renderer_base {
             foreach ($moduleshtml as $modnumber => $modulehtml) {
                 if ($ismoving) {
                     $movingurl = new moodle_url('/course/mod.php', array('moveto' => $modnumber, 'sesskey' => sesskey()));
-                    $sectionoutput .= html_writer::tag('li', html_writer::link($movingurl, $this->output->render($movingpix)),
-                            array('class' => 'movehere', 'title' => $strmovefull));
+                    $sectionoutput .= html_writer::tag('li',
+                            html_writer::link($movingurl, $this->output->render($movingpix), array('title' => $strmovefull)),
+                            array('class' => 'movehere'));
                 }
 
                 $sectionoutput .= $modulehtml;
@@ -1107,8 +1108,9 @@ class core_course_renderer extends plugin_renderer_base {
 
             if ($ismoving) {
                 $movingurl = new moodle_url('/course/mod.php', array('movetosection' => $section->id, 'sesskey' => sesskey()));
-                $sectionoutput .= html_writer::tag('li', html_writer::link($movingurl, $this->output->render($movingpix)),
-                        array('class' => 'movehere', 'title' => $strmovefull));
+                $sectionoutput .= html_writer::tag('li',
+                        html_writer::link($movingurl, $this->output->render($movingpix), array('title' => $strmovefull)),
+                        array('class' => 'movehere'));
             }
         }
 
index 01d6857..781186a 100644 (file)
@@ -25,8 +25,10 @@ Feature: Test we can resort categories in the management interface.
 
   Examples:
     | sortby | cat1 | cat2 | cat3 |
-    | "Sort categories by name"       | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "Sort categories by ID number"   | "Extended social studies" | "Social studies" | "Applied sciences" |
+    | "Sort by Category name ascending"       | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "Sort by Category name descending"      | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "Sort by Category ID number ascending"  | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Category ID number descending" | "Applied sciences"        | "Social studies"          | "Extended social studies" |
 
   Scenario Outline: Test bulk sorting current category.
     Given the following "categories" exist:
@@ -52,8 +54,10 @@ Feature: Test we can resort categories in the management interface.
 
   Examples:
     | sortby | cat1 | cat2 | cat3 |
-    | "Sort categories by name"       | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "Sort categories by ID number"   | "Extended social studies" | "Social studies" | "Applied sciences" |
+    | "Sort by Category name ascending"       | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "Sort by Category name descending"      | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "Sort by Category ID number ascending"  | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Category ID number descending" | "Applied sciences"        | "Social studies"          | "Extended social studies" |
 
   Scenario Outline: Test resorting subcategories.
     Given the following "categories" exist:
@@ -77,8 +81,10 @@ Feature: Test we can resort categories in the management interface.
 
   Examples:
     | sortby | cat1 | cat2 | cat3 |
-    | "resortbyname"            | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "resortbyidnumber"        | "Extended social studies" | "Social studies" | "Applied sciences" |
+    | "resortbyname"         | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "resortbynamedesc"     | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "resortbyidnumber"     | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "resortbyidnumberdesc" | "Applied sciences"        | "Social studies"          | "Extended social studies" |
 
   @javascript
   Scenario Outline: Test resorting subcategories with JS enabled.
@@ -103,8 +109,10 @@ Feature: Test we can resort categories in the management interface.
 
   Examples:
     | sortby | cat1 | cat2 | cat3 |
-    | "resortbyname"            | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "resortbyidnumber"        | "Extended social studies" | "Social studies" | "Applied sciences" |
+    | "resortbyname"         | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "resortbynamedesc"     | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "resortbyidnumber"     | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "resortbyidnumberdesc" | "Applied sciences"        | "Social studies"          | "Extended social studies" |
 
   # The scenario below this is the same but with JS enabled.
   Scenario: Test moving categories up and down by one.
index 818619b..a07af93 100644 (file)
@@ -255,8 +255,10 @@ Feature: Course category management interface performs as expected
 
   Examples:
     | sortby | cat1 | cat2 | cat3 |
-    | "Sort categories by name"       | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "Sort categories by ID number"   | "Extended social studies" | "Social studies" | "Applied sciences" |
+    | "Sort by Category name ascending"       | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "Sort by Category name descending"      | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "Sort by Category ID number ascending"  | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Category ID number descending" | "Applied sciences"        | "Social studies"          | "Extended social studies" |
 
   @javascript
   Scenario Outline: Sub categories are displayed correctly when resorted
@@ -281,8 +283,10 @@ Feature: Course category management interface performs as expected
 
   Examples:
     | sortby | cat1 | cat2 | cat3 |
-    | "resortbyname"            | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "resortbyidnumber"        | "Extended social studies" | "Social studies" | "Applied sciences" |
+    | "resortbyname"         | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "resortbynamedesc"     | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "resortbyidnumber"     | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "resortbyidnumberdesc" | "Applied sciences"        | "Social studies"          | "Extended social studies" |
 
   @javascript
   Scenario Outline: Test courses are displayed correctly after being resorted.
@@ -290,10 +294,10 @@ Feature: Course category management interface performs as expected
       | name | category 0| idnumber |
       | Cat 1 | 0 | CAT1 |
     And the following "courses" exist:
-      | category | fullname | shortname | idnumber | sortorder |
-      | CAT1 | Social studies | Senior school | Ext003 | 1 |
-      | CAT1 | Applied sciences  | Middle school | Sci001 | 2 |
-      | CAT1 | Extended social studies  | Junior school | Ext002 | 3 |
+      | category | fullname | shortname | idnumber | sortorder | timecreated |
+      | CAT1 | Social studies | Senior school | Ext003 | 1 | 10000000001 |
+      | CAT1 | Applied sciences  | Middle school | Sci001 | 2 | 10000000002 |
+      | CAT1 | Extended social studies  | Junior school | Ext002 | 3 | 10000000003 |
 
     And I log in as "admin"
     And I go to the courses management page
@@ -302,9 +306,14 @@ Feature: Course category management interface performs as expected
   # Redirect.
     And I should see the "Course categories and courses" management page
     And I click on "Sort courses" "link"
-    And I should see "By fullname" in the ".course-listing-actions" "css_element"
-    And I should see "By shortname" in the ".course-listing-actions" "css_element"
-    And I should see "By idnumber" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course full name ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course full name descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course short name ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course short name descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course ID number ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course ID number descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course time created ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course time created descending" in the ".course-listing-actions" "css_element"
     And I click on <sortby> "link" in the ".course-listing-actions" "css_element"
   # Redirect.
     And I should see the "Course categories and courses" management page
@@ -313,9 +322,14 @@ Feature: Course category management interface performs as expected
 
   Examples:
     | sortby | course1 | course2 | course3 |
-    | "By fullname"        | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "By shortname"       | "Extended social studies" | "Applied sciences"        | "Social studies" |
-    | "By idnumber"        | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Course full name ascending"     | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "Sort by Course full name descending"    | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "Sort by Course short name ascending"    | "Extended social studies" | "Applied sciences"        | "Social studies" |
+    | "Sort by Course short name descending"   | "Social studies"          | "Applied sciences"        | "Extended social studies" |
+    | "Sort by Course ID number ascending"     | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Course ID number descending"    | "Applied sciences"        | "Social studies"          | "Extended social studies" |
+    | "Sort by Course time created ascending"  | "Social studies"          | "Applied sciences"        | "Extended social studies" |
+    | "Sort by Course time created descending" | "Extended social studies" | "Applied sciences"        | "Social studies" |
 
   @javascript
   Scenario: Test course pagination
@@ -344,7 +358,7 @@ Feature: Course category management interface performs as expected
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I click on "Sort courses" "link"
-    And I click on "By idnumber" "link" in the ".course-listing-actions" "css_element"
+    And I click on "Sort by Course ID number ascending" "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see "Per page: 20" in the ".course-listing-actions" "css_element"
     And I should see course listing "Course 1" before "Course 2"
@@ -527,7 +541,7 @@ Feature: Course category management interface performs as expected
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I click on "Sort courses" "link"
-    And I click on "By idnumber" "link" in the ".course-listing-actions" "css_element"
+    And I click on "Sort by Course ID number ascending" "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see "Per page: 20" in the ".course-listing-actions" "css_element"
     And I should see course listing "Course 1" before "Course 2"
@@ -592,7 +606,7 @@ Feature: Course category management interface performs as expected
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I click on "Sort courses" "link"
-    And I click on "By idnumber" "link" in the ".course-listing-actions" "css_element"
+    And I click on "Sort by Course ID number ascending" "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I should see "Per page: 20" in the ".course-listing-actions" "css_element"
index b530e5b..9cb31a9 100644 (file)
@@ -10,10 +10,10 @@ Feature: Test we can resort course in the management interface.
       | name | category 0| idnumber |
       | Cat 1 | 0 | CAT1 |
     And the following "courses" exist:
-      | category | fullname | shortname | idnumber | sortorder |
-      | CAT1 | Social studies | Senior school | Ext003 | 1 |
-      | CAT1 | Applied sciences  | Middle school | Sci001 | 2 |
-      | CAT1 | Extended social studies  | Junior school | Ext002 | 3 |
+      | category | fullname | shortname | idnumber | sortorder | timecreated |
+      | CAT1 | Social studies | Senior school | Ext003 | 1 | 10000000001 |
+      | CAT1 | Applied sciences  | Middle school | Sci001 | 2 | 10000000002 |
+      | CAT1 | Extended social studies  | Junior school | Ext002 | 3 | 10000000003 |
 
     And I log in as "admin"
     And I go to the courses management page
@@ -22,9 +22,14 @@ Feature: Test we can resort course in the management interface.
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I should see "Sort courses" in the ".course-listing-actions" "css_element"
-    And I should see "By fullname" in the ".course-listing-actions" "css_element"
-    And I should see "By shortname" in the ".course-listing-actions" "css_element"
-    And I should see "By idnumber" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course full name ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course full name descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course short name ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course short name descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course ID number ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course ID number descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course time created ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course time created descending" in the ".course-listing-actions" "css_element"
     And I click on <sortby> "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see the "Course categories and courses" management page
@@ -33,9 +38,14 @@ Feature: Test we can resort course in the management interface.
 
   Examples:
     | sortby | course1 | course2 | course3 |
-    | "By fullname"        | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "By shortname"       | "Extended social studies" | "Applied sciences"        | "Social studies" |
-    | "By idnumber"        | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Course full name ascending"     | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "Sort by Course full name descending"    | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "Sort by Course short name ascending"    | "Extended social studies" | "Applied sciences"        | "Social studies" |
+    | "Sort by Course short name descending"   | "Social studies"          | "Applied sciences"        | "Extended social studies" |
+    | "Sort by Course ID number ascending"     | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Course ID number descending"    | "Applied sciences"        | "Social studies"          | "Extended social studies" |
+    | "Sort by Course time created ascending"  | "Social studies"          | "Applied sciences"        | "Extended social studies" |
+    | "Sort by Course time created descending" | "Extended social studies" | "Applied sciences"        | "Social studies" |
 
   @javascript
   Scenario Outline: Resort courses with JavaScript enabled.
@@ -43,10 +53,10 @@ Feature: Test we can resort course in the management interface.
       | name | category 0| idnumber |
       | Cat 1 | 0 | CAT1 |
     And the following "courses" exist:
-      | category | fullname | shortname | idnumber | sortorder |
-      | CAT1 | Social studies | Senior school | Ext003 | 1 |
-      | CAT1 | Applied sciences  | Middle school | Sci001 | 2 |
-      | CAT1 | Extended social studies  | Junior school | Ext002 | 3 |
+      | category | fullname | shortname | idnumber | sortorder | timecreated |
+      | CAT1 | Social studies | Senior school | Ext003 | 1 | 10000000001 |
+      | CAT1 | Applied sciences  | Middle school | Sci001 | 2 | 10000000002 |
+      | CAT1 | Extended social studies  | Junior school | Ext002 | 3 | 10000000003 |
 
     And I log in as "admin"
     And I go to the courses management page
@@ -55,13 +65,23 @@ Feature: Test we can resort course in the management interface.
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I should see "Sort courses" in the ".course-listing-actions" "css_element"
-    And I should not see "By fullname" in the ".course-listing-actions" "css_element"
-    And I should not see "By shortname" in the ".course-listing-actions" "css_element"
-    And I should not see "By idnumber" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course full name ascending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course full name descending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course short name ascending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course short name descending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course ID number ascending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course ID number descending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course time created ascending" in the ".course-listing-actions" "css_element"
+    And I should not see "Sort by Course time created descending" in the ".course-listing-actions" "css_element"
     And I click on "Sort courses" "link"
-    And I should see "By fullname" in the ".course-listing-actions" "css_element"
-    And I should see "By shortname" in the ".course-listing-actions" "css_element"
-    And I should see "By idnumber" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course full name ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course full name descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course short name ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course short name descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course ID number ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course ID number descending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course time created ascending" in the ".course-listing-actions" "css_element"
+    And I should see "Sort by Course time created descending" in the ".course-listing-actions" "css_element"
     And I click on <sortby> "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see the "Course categories and courses" management page
@@ -70,9 +90,14 @@ Feature: Test we can resort course in the management interface.
 
   Examples:
     | sortby | course1 | course2 | course3 |
-    | "By fullname"        | "Applied sciences"        | "Extended social studies" | "Social studies" |
-    | "By shortname"       | "Extended social studies" | "Applied sciences"        | "Social studies" |
-    | "By idnumber"        | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Course full name ascending"     | "Applied sciences"        | "Extended social studies" | "Social studies" |
+    | "Sort by Course full name descending"    | "Social studies"          | "Extended social studies" | "Applied sciences" |
+    | "Sort by Course short name ascending"    | "Extended social studies" | "Applied sciences"        | "Social studies" |
+    | "Sort by Course short name descending"   | "Social studies"          | "Applied sciences"        | "Extended social studies" |
+    | "Sort by Course ID number ascending"     | "Extended social studies" | "Social studies"          | "Applied sciences" |
+    | "Sort by Course ID number descending"    | "Applied sciences"        | "Social studies"          | "Extended social studies" |
+    | "Sort by Course time created ascending"  | "Social studies"          | "Applied sciences"        | "Extended social studies" |
+    | "Sort by Course time created descending" | "Extended social studies" | "Applied sciences"        | "Social studies" |
 
   Scenario: Test moving courses up and down by one.
     Given the following "categories" exist:
@@ -93,7 +118,7 @@ Feature: Test we can resort course in the management interface.
     And I should see "Course categories" in the "#category-listing h3" "css_element"
     And I should see "Cat 1" in the "#category-listing" "css_element"
     And I click on "Sort courses" "link"
-    And I click on "By idnumber" "link" in the ".course-listing-actions" "css_element"
+    And I click on "Sort by Course ID number ascending" "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I should see course listing "Course 1" before "Course 2"
@@ -130,7 +155,7 @@ Feature: Test we can resort course in the management interface.
     And I should see "Course categories" in the "#category-listing h3" "css_element"
     And I should see "Cat 1" in the "#category-listing" "css_element"
     And I click on "Sort courses" "link"
-    And I click on "By idnumber" "link" in the ".course-listing-actions" "css_element"
+    And I click on "Sort by Course ID number ascending" "link" in the ".course-listing-actions" "css_element"
     # Redirect.
     And I should see the "Course categories and courses" management page
     And I should see course listing "Course 1" before "Course 2"
index 7feea4d..305ba25 100644 (file)
@@ -34,6 +34,14 @@ $capabilities = array(
         'archetypes' => array(
         )
     ),
+    'enrol/category:config' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+        )
+    ),
 );
 
 
index 417b28d..badd2a5 100644 (file)
@@ -22,6 +22,7 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['category:config'] = 'Configure category enrol instances';
 $string['category:synchronised'] = 'Role assignments synchronised to course enrolment';
 $string['pluginname'] = 'Category enrolments';
 $string['pluginname_desc'] = 'Category enrolment plugin is a legacy solution for enrolments at the course category level via role assignments. It is recommended to use cohort synchronisation instead.';
index b806eae..f25b60b 100644 (file)
@@ -38,9 +38,14 @@ class enrol_category_plugin extends enrol_plugin {
      * @param stdClass $instance
      * @return bool
      */
-    public function instance_deleteable($instance) {
+    public function can_delete_instance($instance) {
         global $DB;
 
+        $context = context_course::instance($instance->courseid);
+        if (!has_capability('enrol/database:config', $context)) {
+            return false;
+        }
+
         if (!enrol_is_enabled('category')) {
             return true;
         }
index cb462c0..54262d8 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_category';  // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 60;
index ef6d5ae..e6a3026 100644 (file)
@@ -30,6 +30,18 @@ defined('MOODLE_INTERNAL') || die();
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class enrol_cohort_plugin extends enrol_plugin {
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param stdClass $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/cohort:config', $context);
+    }
+
     /**
      * Returns localised name of enrol instance.
      *
index 7961267..02cf824 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_cohort';    // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 60*60;             // run cron every hour by default, it is not out-of-sync often
index 7dc8ffd..661af04 100644 (file)
@@ -292,7 +292,7 @@ YUI.add('moodle-enrol_cohort-quickenrolment', function(Y) {
                             } else {
                                 if (result.response && result.response.message) {
                                     var alertpanel = new M.core.alert(result.response);
-                                    Y.Node.one('#id_yuialertconfirm-' + alertpanel.COUNT).focus();
+                                    Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
                                 }
                                 var enrolled = Y.Node.create('<div class="'+CSS.COHORTBUTTON+' alreadyenrolled">'+M.str.enrol.synced+'</div>');
                                 node.one('.'+CSS.COHORT+' #cohortid_'+cohort.get(COHORTID)).replace(enrolled);
index 5a6855e..922beb3 100644 (file)
@@ -34,4 +34,12 @@ $capabilities = array(
             'manager' => CAP_ALLOW,
         )
     ),
+    'enrol/database:config' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+        )
+    ),
 );
index 5bae9ea..22efa55 100644 (file)
@@ -22,6 +22,7 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['database:config'] = 'Configure database enrol instances';
 $string['database:unenrol'] = 'Unenrol suspended users';
 $string['dbencoding'] = 'Database encoding';
 $string['dbhost'] = 'Database host';
index 9c51607..de5db32 100644 (file)
@@ -38,7 +38,11 @@ class enrol_database_plugin extends enrol_plugin {
      * @param stdClass $instance
      * @return bool
      */
-    public function instance_deleteable($instance) {
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        if (!has_capability('enrol/database:config', $context)) {
+            return false;
+        }
         if (!enrol_is_enabled('database')) {
             return true;
         }
index b4cfdcf..9dff389 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_database';  // Full name of the plugin (used for diagnostics)
 //TODO: should we add cron sync?
index 335a766..fa46832 100644 (file)
@@ -101,8 +101,9 @@ class enrol_flatfile_plugin extends enrol_plugin {
      * @param object $instance
      * @return bool
      */
-    public function instance_deleteable($instance) {
-        return true;
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/flatfile:manage', $context);
     }
 
     /**
index 5289f09..05fb255 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_flatfile';  // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 60;
index 2f0d444..df60177 100644 (file)
@@ -391,4 +391,16 @@ class enrol_guest_plugin extends enrol_plugin {
         // No need to set mapping, we do not restore users or roles here.
         $step->set_mapping('enrol', $oldid, 0);
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/guest:config', $context);
+    }
+
 }
index b506dd2..1ef76e0 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_guest';     // Full name of the plugin (used for diagnostics)
diff --git a/enrol/imsenterprise/db/access.php b/enrol/imsenterprise/db/access.php
new file mode 100644 (file)
index 0000000..09b9a44
--- /dev/null
@@ -0,0 +1,37 @@
+<?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/>.
+
+/**
+ * Capabilities for imsenterprise enrolment plugin.
+ *
+ * @package    enrol_imsenterprise
+ * @copyright  2014 Daniel Neis Araujo
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+    'enrol/imsenterprise:config' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+        )
+    ),
+);
+
index 8564667..b7a8659 100644 (file)
@@ -46,6 +46,7 @@ $string['filelockedmail'] = 'The text file you are using for IMS-file-based enro
 $string['filelockedmailsubject'] = 'Important error: Enrolment file';
 $string['fixcasepersonalnames'] = 'Change personal names to Title Case';
 $string['fixcaseusernames'] = 'Change usernames to lower case';
+$string['imsenterprise:config'] = 'Configure IMS Enterprise enrol instances';
 $string['imsrolesdescription'] = 'The IMS Enterprise specification includes 8 distinct role types. Please choose how you want them to be assigned in Moodle, including whether any of them should be ignored.';
 $string['location'] = 'File location';
 $string['logtolocation'] = 'Log file output location (blank for no logging)';
index 6db0851..8b98a92 100644 (file)
@@ -270,13 +270,16 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
      * @param string $tagcontents The raw contents of the XML element
      */
     protected function process_group_tag($tagcontents) {
-        global $DB;
+        global $DB, $CFG;
 
         // Get configs.
         $truncatecoursecodes    = $this->get_config('truncatecoursecodes');
         $createnewcourses       = $this->get_config('createnewcourses');
         $createnewcategories    = $this->get_config('createnewcategories');
 
+        if ($createnewcourses) {
+            require_once("$CFG->dirroot/course/lib.php");
+        }
         // Process tag contents.
         $group = new stdClass();
         if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $tagcontents, $matches)) {
@@ -788,4 +791,15 @@ class enrol_imsenterprise_plugin extends enrol_plugin {
 
         return $defaultcategoryid;
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/imsenterprise:config', $context);
+    }
 }
index 6d978c6..6ab78fb 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;
-$plugin->requires  = 2014050800;
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_imsenterprise';
 $plugin->cron      = 60;
index 09ed549..825a9e8 100644 (file)
@@ -96,34 +96,52 @@ if ($canconfig and $action and confirm_sesskey()) {
             $instance = $instances[$instanceid];
             $plugin = $plugins[$instance->enrol];
 
-            if ($confirm) {
-                if (enrol_accessing_via_instance($instance)) {
-                    if (!$confirm2) {
-                        $yesurl = new moodle_url('/enrol/instances.php', array('id'=>$course->id, 'action'=>'delete', 'instance'=>$instance->id, 'confirm'=>1, 'confirm2'=>1, 'sesskey'=>sesskey()));
-                        $displayname = $plugin->get_instance_name($instance);
-                        $message = markdown_to_html(get_string('deleteinstanceconfirmself', 'enrol', array('name'=>$displayname)));
-                        echo $OUTPUT->header();
-                        echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
-                        echo $OUTPUT->footer();
-                        die();
+            if ($plugin->can_delete_instance($instance)) {
+                if ($confirm) {
+                    if (enrol_accessing_via_instance($instance)) {
+                        if (!$confirm2) {
+                            $yesurl = new moodle_url('/enrol/instances.php',
+                                                     array('id' => $course->id,
+                                                           'action' => 'delete',
+                                                           'instance' => $instance->id,
+                                                           'confirm' => 1,
+                                                           'confirm2' => 1,
+                                                           'sesskey' => sesskey()));
+                            $displayname = $plugin->get_instance_name($instance);
+                            $message = markdown_to_html(get_string('deleteinstanceconfirmself',
+                                                                   'enrol',
+                                                                   array('name' => $displayname)));
+                            echo $OUTPUT->header();
+                            echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
+                            echo $OUTPUT->footer();
+                            die();
+                        }
                     }
+                    $plugin->delete_instance($instance);
+                    redirect($PAGE->url);
                 }
-                $plugin->delete_instance($instance);
-                redirect($PAGE->url);
-            }
 
-            echo $OUTPUT->header();
-            $yesurl = new moodle_url('/enrol/instances.php', array('id'=>$course->id, 'action'=>'delete', 'instance'=>$instance->id, 'confirm'=>1,'sesskey'=>sesskey()));
-            $displayname = $plugin->get_instance_name($instance);
-            $users = $DB->count_records('user_enrolments', array('enrolid'=>$instance->id));
-            if ($users) {
-                $message = markdown_to_html(get_string('deleteinstanceconfirm', 'enrol', array('name'=>$displayname, 'users'=>$users)));
-            } else {
-                $message = markdown_to_html(get_string('deleteinstancenousersconfirm', 'enrol', array('name'=>$displayname)));
+                echo $OUTPUT->header();
+                $yesurl = new moodle_url('/enrol/instances.php',
+                                         array('id' => $course->id,
+                                               'action' => 'delete',
+                                               'instance' => $instance->id,
+                                               'confirm' => 1,
+                                               'sesskey' => sesskey()));
+                $displayname = $plugin->get_instance_name($instance);
+                $users = $DB->count_records('user_enrolments', array('enrolid' => $instance->id));
+                if ($users) {
+                    $message = markdown_to_html(get_string('deleteinstanceconfirm', 'enrol',
+                                                           array('name' => $displayname,
+                                                                 'users' => $users)));
+                } else {
+                    $message = markdown_to_html(get_string('deleteinstancenousersconfirm', 'enrol',
+                                                           array('name' => $displayname)));
+                }
+                echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
+                echo $OUTPUT->footer();
+                die();
             }
-            echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
-            echo $OUTPUT->footer();
-            die();
 
         } else if ($action === 'disable') {
             $instance = $instances[$instanceid];
@@ -212,8 +230,7 @@ foreach ($instances as $instance) {
         }
         ++$updowncount;
 
-        // edit links
-        if ($plugin->instance_deleteable($instance)) {
+        if ($plugin->can_delete_instance($instance)) {
             $aurl = new moodle_url($url, array('action'=>'delete', 'instance'=>$instance->id));
             $edit[] = $OUTPUT->action_icon($aurl, new pix_icon('t/delete', $strdelete, 'core', array('class' => 'iconsmall')));
         }
@@ -234,7 +251,7 @@ foreach ($instances as $instance) {
     }
 
     // link to instance management
-    if (enrol_is_enabled($instance->enrol)) {
+    if (enrol_is_enabled($instance->enrol) && $canconfig) {
         if ($icons = $plugin->get_action_icons($instance)) {
             $edit = array_merge($edit, $icons);
         }
index b4bf0b9..21d5b1e 100644 (file)
@@ -106,7 +106,12 @@ class enrol_ldap_plugin extends enrol_plugin {
      * @param object $instance
      * @return bool
      */
-    public function instance_deleteable($instance) {
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        if (!has_capability('enrol/database:config', $context)) {
+            return false;
+        }
+
         if (!enrol_is_enabled('ldap')) {
             return true;
         }
@@ -1155,4 +1160,3 @@ class enrol_ldap_plugin extends enrol_plugin {
         }
     }
 }
-
index a1b47dc..76505ab 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_ldap';      // Full name of the plugin (used for diagnostics)
index 805ed05..4066f9d 100644 (file)
@@ -553,4 +553,15 @@ class enrol_manual_plugin extends enrol_plugin {
 
         groups_add_member($groupid, $userid);
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/manual:config', $context);
+    }
 }
index 4089156..963d30d 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_manual';    // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 600;
index 258232a..30d2731 100644 (file)
@@ -148,5 +148,16 @@ class enrol_meta_plugin extends enrol_plugin {
         require_once("$CFG->dirroot/enrol/meta/locallib.php");
         enrol_meta_sync();
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/meta:config', $context);
+    }
 }
 
index 1fab182..4951f33 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_meta';      // Full name of the plugin (used for diagnostics)
-$plugin->cron      = 60*60;             // run cron every hour by default, it is not out-of-sync often
\ No newline at end of file
+$plugin->cron      = 60*60;             // run cron every hour by default, it is not out-of-sync often
diff --git a/enrol/mnet/db/access.php b/enrol/mnet/db/access.php
new file mode 100644 (file)
index 0000000..f980979
--- /dev/null
@@ -0,0 +1,36 @@
+<?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/>.
+
+/**
+ * Capabilities for mnet enrolment plugin.
+ *
+ * @package    enrol_mnet
+ * @copyright  2014 Daniel Neis Araujo
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+    'enrol/mnet:config' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+        )
+    ),
+);
index 9f086d1..2fb3ed0 100644 (file)
@@ -25,6 +25,7 @@
 $string['error_multiplehost'] = 'Some instance of MNet enrolment plugin already exists for this host. Only one instance per host and/or one instance for \'All hosts\' is allowed.';
 $string['instancename'] = 'Enrolment method name';
 $string['instancename_help'] = 'You can optionally rename this instance of the MNet enrolment method. If you leave this field empty, the default instance name will be used, containing the name of the remote host and the assigned role for their users.';
+$string['mnet:config'] = 'Configure MNet enrol instances';
 $string['mnet_enrol_description'] = 'Publish this service to allow administrators at {$a} to enrol their students in courses you have created on your server.<br/><ul><li><em>Dependency</em>: You must also <strong>subscribe</strong> to the SSO (Identity Provider) service on {$a}.</li><li><em>Dependency</em>: You must also <strong>publish</strong> the SSO (Service Provider) service to {$a}.</li></ul><br/>Subscribe to this service to be able to enrol your students in courses  on {$a}.<br/><ul><li><em>Dependency</em>: You must also <strong>publish</strong> the SSO (Identity Provider) service to {$a}.</li><li><em>Dependency</em>: You must also <strong>subscribe</strong> to the SSO (Service Provider) service on {$a}.</li></ul><br/>';
 $string['mnet_enrol_name'] = 'Remote enrolment service';
 $string['pluginname'] = 'MNet remote enrolments';
index 28578a2..2d3c55b 100644 (file)
@@ -88,4 +88,15 @@ class enrol_mnet_plugin extends enrol_plugin {
 
         return new moodle_url('/enrol/mnet/addinstance.php', array('id'=>$courseid));
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/mnet:config', $context);
+    }
 }
index 8caa9a8..c78a309 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_mnet';      // Full name of the plugin (used for diagnostics)
index f3762d7..71ac2e4 100644 (file)
@@ -307,4 +307,15 @@ class enrol_paypal_plugin extends enrol_plugin {
         $this->process_expirations($trace);
         return 0;
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/paypal:config', $context);
+    }
 }
index 4fd1649..abce57d 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_paypal';    // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 60;
index edc114f..e2ad583 100644 (file)
@@ -644,4 +644,15 @@ class enrol_self_plugin extends enrol_plugin {
         // we do not use component in manual or self enrol.
         role_assign($roleid, $userid, $contextid, '', 0);
     }
+
+    /**
+     * Is it possible to delete enrol instance via standard UI?
+     *
+     * @param object $instance
+     * @return bool
+     */
+    public function can_delete_instance($instance) {
+        $context = context_course::instance($instance->courseid);
+        return has_capability('enrol/self:config', $context);
+    }
 }
index 9e01613..47de8ce 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014051200;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2014050800;        // Requires this Moodle version
+$plugin->version   = 2014072200;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2014072200;        // Requires this Moodle version
 $plugin->component = 'enrol_self';      // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 600;
index dc6d2c0..2bed0e7 100644 (file)
@@ -1,6 +1,10 @@
 This files describes API changes in /enrol/* - plugins,
 information provided here is intended especially for developers.
 
+=== 2.8 ===
+
+* enrol_plugin::instance_deleteable() is deprecated and has been replaced by enrol_plugin::can_delete_instance()
+
 === 2.6 ===
 
 * Enrolment plugin which supports self enrolment should implement can_self_enrol()
index 7623b14..b497034 100644 (file)
@@ -602,13 +602,13 @@ class core_files_renderer extends plugin_renderer_base {
                     <div class="fp-tb-message"></div>
                 </div>
                 <div class="fp-viewbar">
-                    <a title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
+                    <a role="button" title="'. get_string('displayicons', 'repository') .'" class="fp-vb-icons" href="#">
                         <img alt="" src="'. $this->pix_url('fp/view_icon_active', 'theme') .'" />
                     </a>
-                    <a title="'. get_string('displaydetails', 'repository') .'" class="fp-vb-details" href="#">
+                    <a role="button" title="'. get_string('displaydetails', 'repository') .'" class="fp-vb-details" href="#">
                         <img alt="" src="'. $this->pix_url('fp/view_list_active', 'theme') .'" />
                     </a>
-                    <a title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
+                    <a role="button" title="'. get_string('displaytree', 'repository') .'" class="fp-vb-tree" href="#">
                         <img alt="" src="'. $this->pix_url('fp/view_tree_active', 'theme') .'" />
                     </a>
                 </div>
index 0f46959..d9ce6f7 100644 (file)
@@ -74,11 +74,12 @@ class filter_activitynames extends moodle_text_filter {
                             'name' => $cm->name,
                             'url' => $cm->url,
                             'id' => $cm->id,
-                            'namelen' => strlen($cm->name),
+                            'namelen' => -strlen($cm->name), // Negative value for reverse sorting.
                         );
                     }
                 }
-                core_collator::asort_objects_by_property($sortedactivities, 'namelen', SORT_NUMERIC);
+                // Sort activities by the length of the activity name in reverse order.
+                core_collator::asort_objects_by_property($sortedactivities, 'namelen', core_collator::SORT_NUMERIC);
 
                 foreach ($sortedactivities as $cm) {
                     $title = s(trim(strip_tags($cm->name)));
index 05eae5d..924837f 100644 (file)
@@ -34,6 +34,8 @@
 
 defined('MOODLE_INTERNAL') || die;
 
+require_once($CFG->libdir . '/classes/useragent.php');
+
 /**
  * Create TeX image link.
  *
@@ -100,6 +102,7 @@ function filter_text_image($imagefile, $tex, $height, $width, $align, $alt) {
         $action = new popup_action('click', $link, 'popup', array('width'=>320,'height'=>240));
     }
     $output = $OUTPUT->action_link($link, $anchorcontents, $action, array('title'=>'TeX')); //TODO: the popups do not work when text caching is enabled!!
+    $output = "<span class=\"MathJax_Preview\">$output</span><script type=\"math/tex\">$tex</script>";
 
     return $output;
 }
@@ -197,6 +200,9 @@ class filter_tex extends moodle_text_filter {
                 $DB->insert_record("cache_filters", $texcache, false);
             }
             $convertformat = get_config('filter_tex', 'convertformat');
+            if ($convertformat == 'svg' && !core_useragent::supports_svg()) {
+                $convertformat = 'png';
+            }
             $filename = $md5.".{$convertformat}";
             $text = str_replace( $matches[0][$i], filter_text_image($filename, $texexp, 0, 0, $align, $alt), $text);
         }
index 49fe7d1..c06a83d 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-$string['configconvertformat'] = 'If <i>latex</i>, <i>dvips</i> and <i>convert</i> are available, the images are created using the specified format. If it is not, mimeTeX will be used and it will create GIF images.';
-$string['convertformat'] = '<i>Convert</i> output format';
+$string['configconvertformat'] = 'If <i>latex</i> and <i>dvips</i> and are available, they are used to GIF or PNG images if <i>convert</i> is also available or if <i>dvisvgm</i> is available SVG images as specified. Otherwise <i>mimeTeX</i> will be used, and it will create GIF images.';
+$string['convertformat'] = 'Output image format';
 $string['latexpreamble'] = 'LaTeX preamble';
 $string['latexsettings'] = 'LaTeX renderer Settings';
 $string['filtername'] = 'TeX notation';
 $string['pathconvert'] = 'Path of <i>convert</i> binary';
 $string['pathdvips'] = 'Path of <i>dvips</i> binary';
+$string['pathdvisvgm'] = 'Path of <i>dvisvgm</i> binary';
 $string['pathlatex'] = 'Path of <i>latex</i> binary';
 $string['pathmimetex'] = 'Path of <i>mimetex</i> binary';
 $string['pathmimetexdesc'] = 'Moodle will use its own mimetex binary unless another valid path is specified.';
index a79a33e..a1966da 100644 (file)
@@ -78,7 +78,7 @@
         /**
          * Render TeX string into gif/png
          * @param string $formula TeX formula
-         * @param string $filename base of filename for output (no extension)
+         * @param string $filename filename for output (including extension)
          * @param int $fontsize font size
          * @param int $density density value for .ps to .gif/.png conversion
          * @param string $background background color (e.g, #FFFFFF).
             if (empty($pathlatex)) {
                 return false;
             }
+            $pathlatex = escapeshellarg(trim($pathlatex, " '\""));
 
             $doc = $this->construct_latex_document( $formula, $fontsize );
 
             // construct some file paths
+            $convertformat = get_config('filter_tex', 'convertformat');
+            if (!strpos($filename, ".{$convertformat}")) {
+                $convertformat = 'png';
+            }
+            $filename = str_replace(".{$convertformat}", '', $filename);
             $tex = "{$this->temp_dir}/$filename.tex";
             $dvi = "{$this->temp_dir}/$filename.dvi";
             $ps  = "{$this->temp_dir}/$filename.ps";
-            $convertformat = get_config('filter_tex', 'convertformat');
             $img = "{$this->temp_dir}/$filename.{$convertformat}";
 
             // turn the latex doc into a .tex file in the temp area
             fclose( $fh );
 
             // run latex on document
-            $command = "{$pathlatex} --interaction=nonstopmode --halt-on-error $tex";
+            $command = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
             chdir( $this->temp_dir );
             if ($this->execute($command, $log)) { // It allways False on Windows
 //                return false;
             }
 
             // run dvips (.dvi to .ps)
-            $pathdvips = get_config('filter_tex', 'pathdvips');
-            $command = "{$pathdvips} -E $dvi -o $ps";
+            $pathdvips = escapeshellarg(trim(get_config('filter_tex', 'pathdvips'), " '\""));
+            $command = "$pathdvips -E $dvi -o $ps";
             if ($this->execute($command, $log )) {
                 return false;
             }
 
-            // run convert on document (.ps to .gif/.png)
+            // Run convert on document (.ps to .gif/.png) or run dvisvgm (.ps to .svg).
             if ($background) {
                 $bg_opt = "-transparent \"$background\""; // Makes transparent background
             } else {
                 $bg_opt = "";
             }
-            $pathconvert = get_config('filter_tex', 'pathconvert');
-            $command = "{$pathconvert} -density $density -trim $bg_opt $ps $img";
+            if ($convertformat == 'svg') {
+                $pathdvisvgm = escapeshellarg(trim(get_config('filter_tex', 'pathdvisvgm'), " '\""));
+                $command = "$pathdvisvgm -E $ps -o $img";
+            } else {
+                $pathconvert = escapeshellarg(trim(get_config('filter_tex', 'pathconvert'), " '\""));
+                $command = "$pathconvert -density $density -trim $bg_opt $ps $img";
+            }
             if ($this->execute($command, $log )) {
                 return false;
             }
index b77dfae..4aad3ec 100644 (file)
@@ -125,15 +125,24 @@ function filter_tex_updatedcallback($name) {
         return;
     }
 
-    $pathdvips = get_config('filter_tex', 'pathdvips');
-    $pathconvert = get_config('filter_tex', 'pathconvert');
-
-    if (!(is_file($pathlatex) && is_executable($pathlatex) &&
-          is_file($pathdvips) && is_executable($pathdvips) &&
-          is_file($pathconvert) && is_executable($pathconvert))) {
-        // LaTeX, dvips or convert are not available, and mimetex can only produce GIFs so...
-        set_config('convertformat', 'gif', 'filter_tex');
+    $pathlatex = trim($pathlatex, " '\"");
+    $pathdvips = trim(get_config('filter_tex', 'pathdvips'), " '\"");
+    $pathconvert = trim(get_config('filter_tex', 'pathconvert'), " '\"");
+    $pathdvisvgm = trim(get_config('filter_tex', 'pathdvisvgm'), " '\"");
+
+    $supportedformats = array('gif');
+    if ((is_file($pathlatex) && is_executable($pathlatex)) &&
+            (is_file($pathdvips) && is_executable($pathdvips))) {
+        if (is_file($pathconvert) && is_executable($pathconvert)) {
+             $supportedformats[] = 'png';
+        }
+        if (is_file($pathdvisvgm) && is_executable($pathdvisvgm)) {
+             $supportedformats[] = 'svg';
+        }
+    }
+    if (!in_array(get_config('filter_tex', 'convertformat'), $supportedformats)) {
+        set_config('convertformat', array_pop($supportedformats), 'filter_tex');
     }
-}
 
+}
 
index 43c9d1a..d66faf2 100644 (file)
@@ -33,6 +33,9 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
 
     if (!file_exists($pathname)) {
         $convertformat = get_config('filter_tex', 'convertformat');
+        if (strpos($image, '.png')) {
+            $convertformat = 'png';
+        }
         $md5 = str_replace(".{$convertformat}", '', $image);
         if ($texcache = $DB->get_record('cache_filters', array('filter'=>'tex', 'md5key'=>$md5))) {
             if (!file_exists($CFG->dataroot.'/filter/tex')) {
@@ -44,9 +47,9 @@ define('NO_MOODLE_COOKIES', true); // Because it interferes with caching
             $density = get_config('filter_tex', 'density');
             $background = get_config('filter_tex', 'latexbackground');
             $texexp = $texcache->rawtext; // the entities are now decoded before inserting to DB
-            $latex_path = $latex->render($texexp, $md5, 12, $density, $background);
-            if ($latex_path) {
-                copy($latex_path, $pathname);
+            $lateximage = $latex->render($texexp, $image, 12, $density, $background);
+            if ($lateximage) {
+                copy($lateximage, $pathname);
                 $latex->clean_up($md5);
 
             } else {
index 6c79a21..e0d5ddc 100644 (file)
@@ -36,39 +36,53 @@ if ($ADMIN->fulltree) {
     $items[] = new admin_setting_configtext('filter_tex/latexbackground', get_string('backgroundcolour', 'admin'), '', '#FFFFFF');
     $items[] = new admin_setting_configtext('filter_tex/density', get_string('density', 'admin'), '', '120', PARAM_INT);
 
+    $default_filter_tex_pathlatex   = '';
+    $default_filter_tex_pathdvips   = '';
+    $default_filter_tex_pathdvisvgm = '';
+    $default_filter_tex_pathconvert = '';
     if (PHP_OS=='Linux') {
         $default_filter_tex_pathlatex   = "/usr/bin/latex";
         $default_filter_tex_pathdvips   = "/usr/bin/dvips";
+        $default_filter_tex_pathdvisvgm = "/usr/bin/dvisvgm";
         $default_filter_tex_pathconvert = "/usr/bin/convert";
-
     } else if (PHP_OS=='Darwin') {
         // most likely needs a fink install (fink.sf.net)
         $default_filter_tex_pathlatex   = "/sw/bin/latex";
         $default_filter_tex_pathdvips   = "/sw/bin/dvips";
+        $default_filter_tex_pathdvisvgm = "/usr/bin/dvisvgm";
         $default_filter_tex_pathconvert = "/sw/bin/convert";
 
     } else if (PHP_OS=='WINNT' or PHP_OS=='WIN32' or PHP_OS=='Windows') {
         // note: you need Ghostscript installed (standard), miktex (standard)
         // and ImageMagick (install at c:\ImageMagick)
-        $default_filter_tex_pathlatex   = "\"c:\\texmf\\miktex\\bin\\latex.exe\" ";
-        $default_filter_tex_pathdvips   = "\"c:\\texmf\\miktex\\bin\\dvips.exe\" ";
-        $default_filter_tex_pathconvert = "\"c:\\imagemagick\\convert.exe\" ";
+        $default_filter_tex_pathlatex   = "c:\\texmf\\miktex\\bin\\latex.exe";
+        $default_filter_tex_pathdvips   = "c:\\texmf\\miktex\\bin\\dvips.exe";
+        $default_filter_tex_pathdvisvgm   = "c:\\texmf\\miktex\\bin\\dvisvgm.exe";
+        $default_filter_tex_pathconvert = "c:\\imagemagick\\convert.exe";
+    }
 
-    } else {
-        $default_filter_tex_pathlatex   = '';
-        $default_filter_tex_pathdvips   = '';
-        $default_filter_tex_pathconvert = '';
+    $pathlatex = get_config('filter_tex', 'pathlatex');
+    $pathdvips = get_config('filter_tex', 'pathdvips');
+    $pathconvert = get_config('filter_tex', 'pathconvert');
+    $pathdvisvgm = get_config('filter_tex', 'pathdvisvgm');
+    if (strrpos($pathlatex . $pathdvips . $pathconvert . $pathdvisvgm, '"') or
+            strrpos($pathlatex . $pathdvips . $pathconvert . $pathdvisvgm, "'")) {
+        set_config('pathlatex', trim($pathlatex, " '\""), 'filter_tex');
+        set_config('pathdvips', trim($pathdvips, " '\""), 'filter_tex');
+        set_config('pathconvert', trim($pathconvert, " '\""), 'filter_tex');
+        set_config('pathdvisvgm', trim($pathdvisvgm, " '\""), 'filter_tex');
     }
 
     $items[] = new admin_setting_configexecutable('filter_tex/pathlatex', get_string('pathlatex', 'filter_tex'), '', $default_filter_tex_pathlatex);
     $items[] = new admin_setting_configexecutable('filter_tex/pathdvips', get_string('pathdvips', 'filter_tex'), '', $default_filter_tex_pathdvips);
     $items[] = new admin_setting_configexecutable('filter_tex/pathconvert', get_string('pathconvert', 'filter_tex'), '', $default_filter_tex_pathconvert);
+    $items[] = new admin_setting_configexecutable('filter_tex/pathdvisvgm', get_string('pathdvisvgm', 'filter_tex'), '', $default_filter_tex_pathdvisvgm);
     $items[] = new admin_setting_configexecutable('filter_tex/pathmimetex', get_string('pathmimetex', 'filter_tex'), get_string('pathmimetexdesc', 'filter_tex'), '');
 
-    // Even if we offer GIF and PNG formats here, in the update callback we check whether
-    // all the paths actually point to executables. If they don't, we force the setting
+    // Even if we offer GIF, PNG and SVG formats here, in the update callback we check whether
+    // required paths actually point to executables. If they don't, we force the setting
     // to GIF, as that's the only format mimeTeX can produce.
-    $formats = array('gif' => 'GIF', 'png' => 'PNG');
+    $formats = array('gif' => 'GIF', 'png' => 'PNG', 'svg' => 'SVG');
     $items[] = new admin_setting_configselect('filter_tex/convertformat', get_string('convertformat', 'filter_tex'), get_string('configconvertformat', 'filter_tex'), 'gif', $formats);
 
     foreach ($items as $item) {
index 51588da..ad28cbc 100644 (file)
 
         // first check if it is likely to work at all
         $output .= "<h3>Checking executables</h3>\n";
-        $executables_exist = true;
-        $pathlatex = get_config('filter_tex', 'pathlatex');
+        $executablesexist = true;
+        $pathlatex = trim(get_config('filter_tex', 'pathlatex'), " '\"");
         if (is_file($pathlatex)) {
             $output .= "latex executable ($pathlatex) is readable<br />\n";
-        }
-        else {
-            $executables_exist = false;
+        } else {
+            $executablesexist = false;
             $output .= "<b>Error:</b> latex executable ($pathlatex) is not readable<br />\n";
         }
-        $pathdvips = get_config('filter_tex', 'pathdvips');
+        $pathdvips = trim(get_config('filter_tex', 'pathdvips'), " '\"");
         if (is_file($pathdvips)) {
             $output .= "dvips executable ($pathdvips) is readable<br />\n";
-        }
-        else {
-            $executables_exist = false;
+        } else {
+            $executablesexist = false;
             $output .= "<b>Error:</b> dvips executable ($pathdvips) is not readable<br />\n";
         }
-        $pathconvert = get_config('filter_tex', 'pathconvert');
+        $pathconvert = trim(get_config('filter_tex', 'pathconvert'), " '\"");
         if (is_file($pathconvert)) {
             $output .= "convert executable ($pathconvert) is readable<br />\n";
-        }
-        else {
-            $executables_exist = false;
+        } else {
+            $executablesexist = false;
             $output .= "<b>Error:</b> convert executable ($pathconvert) is not readable<br />\n";
         }
+        $pathdvisvgm = trim(get_config('filter_tex', 'pathdvisvgm'), " '\"");
+        if (is_file($pathdvisvgm)) {
+            $output .= "dvisvgm executable ($pathdvisvgm) is readable<br />\n";
+        } else {
+            $executablesexist = false;
+            $output .= "<b>Error:</b> dvisvgm executable ($pathdvisvgm) is not readable<br />\n";
+        }
 
         // knowing that it might work..
         $md5 = md5($expression);
         chdir($latex->temp_dir);
 
         // step 1: latex command
+        $pathlatex = escapeshellarg($pathlatex);
         $cmd = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
         $output .= execute($cmd);
 
         // step 2: dvips command
+        $pathdvips = escapeshellarg($pathdvips);
         $cmd = "$pathdvips -E $dvi -o $ps";
         $output .= execute($cmd);
 
-        // step 3: convert command
-        $cmd = "$pathconvert -density 240 -trim $ps $img ";
+        // Step 3: Set convert or dvisvgm command.
+        if ($convertformat == 'svg') {
+            $pathdvisvgm = escapeshellarg($pathdvisvgm);
+            $cmd = "$pathdvisvgm -E $ps -o $img";
+        } else {
+            $pathconvert = escapeshellarg($pathconvert);
+            $cmd = "$pathconvert -density 240 -trim $ps $img ";
+        }
         $output .= execute($cmd);
 
         if (!$graphic) {
             echo $output;
-        } else if (file_exists($img)){
+        } else if (file_exists($img)) {
             send_file($img, "$md5.{$convertformat}");
         } else {
             echo "Error creating image, see command execution output for more details.";
@@ -338,7 +350,7 @@ searches the database cache_filters table to see if this TeX expression had been
 processed before. If not, it adds a DB entry for that expression.  It then
 replaces the TeX expression by an &lt;img src=&quot;.../filter/tex/pix.php...&quot;&gt;
 tag.  The filter/tex/pix.php script then searches the database to find an
-appropriate gif/png image file for that expression and to create one if it doesn't exist.
+appropriate gif/png/svg image file for that expression and to create one if it doesn't exist.
 It will then use either the LaTex/Ghostscript renderer (using external executables
 on your system) or the bundled Mimetex executable. The full Latex/Ghostscript
 renderer produces better results and is tried first.
@@ -349,7 +361,7 @@ you might try to fix them.</p>
 process this expression. Then the database entry for that expression contains
 a bad TeX expression in the rawtext field (usually blank). You can fix this
 by clicking on &quot;Delete DB Entry&quot;</li>
-<li>The TeX to gif/png image conversion process does not work.
+<li>The TeX to gif/png/svg image conversion process does not work.
 If paths are specified in the filter configuation screen for the three
 executables these will be tried first. Note that they still must be correctly
 installed and have the correct permissions. In particular make sure that you
index 0a4b562..6c957c8 100644 (file)
@@ -85,7 +85,7 @@ if ($editform->is_cancelled()) {
         default:
             print_error('unknoworder');
     }
-    $users = groups_get_potential_members($data->courseid, $data->roleid, $data->cohortid, $orderby);
+    $users = groups_get_potential_members($data->courseid, $data->roleid, $data->cohortid, $orderby, !empty($data->notingroup));
     $usercnt = count($users);
 
     if ($data->allocateby == 'random') {
index c62c390..d874911 100644 (file)
@@ -110,6 +110,8 @@ class autogroup_form extends moodleform {
         $mform->addElement('checkbox', 'nosmallgroups', get_string('nosmallgroups', 'group'));
         $mform->disabledIf('nosmallgroups', 'groupby', 'noteq', 'members');
 
+        $mform->addElement('checkbox', 'notingroup', get_string('notingroup', 'group'));
+
         $mform->addElement('header', 'groupinghdr', get_string('grouping', 'group'));
 
         $options = array('0' => get_string('nogrouping', 'group'),
index 970ce78..7d44a43 100644 (file)
@@ -709,23 +709,42 @@ function groups_get_possible_roles($context) {
  * @param int $roleid The role to select users from
  * @param int $cohortid restrict to cohort id
  * @param string $orderby The column to sort users by
+ * @param int $notingroup restrict to users not in existing groups
  * @return array An array of the users
  */
-function groups_get_potential_members($courseid, $roleid = null, $cohortid = null, $orderby = 'lastname ASC, firstname ASC') {
+function groups_get_potential_members($courseid, $roleid = null, $cohortid = null,
+                                      $orderby = 'lastname ASC, firstname ASC',
+                                      $notingroup = null) {
     global $DB;
 
     $context = context_course::instance($courseid);
 
     list($esql, $params) = get_enrolled_sql($context);
 
+    $notingroupsql = "";
+    if ($notingroup) {
+        // We want to eliminate users that are already associated with a course group.
+        $notingroupsql = "u.id NOT IN (SELECT userid
+                                         FROM {groups_members}
+                                        WHERE groupid IN (SELECT id
+                                                            FROM {groups}
+                                                           WHERE courseid = :courseid))";
+        $params['courseid'] = $courseid;
+    }
+
     if ($roleid) {
         // We are looking for all users with this role assigned in this context or higher.
-        list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx');
+        list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true),
+                                                                       SQL_PARAMS_NAMED,
+                                                                       'relatedctx');
 
         $params = array_merge($params, $relatedctxparams, array('roleid' => $roleid));
         $where = "WHERE u.id IN (SELECT userid
                                    FROM {role_assignments}
                                   WHERE roleid = :roleid AND contextid $relatedctxsql)";
+        $where .= $notingroup ? "AND $notingroupsql" : "";
+    } else if ($notingroup) {
+        $where = "WHERE $notingroupsql";
     } else {
         $where = "";
     }
index a49d13f..ee7f6b0 100644 (file)
@@ -84,3 +84,28 @@ Feature: Automatic creation of groups
     And I should see "Group B" in the ".generaltable" "css_element"
     And I should see "5" in the "Group A" "table_row"
     And I should see "5" in the "Group B" "table_row"
+
+  @javascript
+  Scenario: Split automatically the course users in groups that are not in groups
+    Given I press "Cancel"
+    And I press "Create group"
+    And I set the following fields to these values:
+      | Group name | Group 1 |
+    And I press "Save changes"
+    And I press "Create group"
+    And I set the following fields to these values:
+      | Group name | Group 2 |
+    And I press "Save changes"
+    When I add "Student 0" user to "Group 1" group members
+    And I add "Student 1" user to "Group 1" group members
+    And I add "Student 2" user to "Group 2" group members
+    And I add "Student 3" user to "Group 2" group members
+    And I press "Auto-create groups"
+    And I expand all fieldsets
+    And I set the field "Auto create based on" to "Number of groups"
+    And I set the field "Group/member count" to "2"
+    And I set the field "Grouping of auto-created groups" to "No grouping"
+    And I set the field "Ignore users in groups" to "1"
+    And I press "Submit"
+    And the "groups" select box should contain "Group A (3)"
+    And the "groups" select box should contain "Group B (3)"
\ No newline at end of file
diff --git a/install/lang/af/moodle.php b/install/lang/af/moodle.php
new file mode 100644 (file)
index 0000000..e9fb8fd
--- /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 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['language'] = 'Taal';
index b9211b2..bd3678e 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['admindirname'] = 'Ð\9aаÑ\82алог Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80а';
+$string['admindirname'] = 'Ð\9aаÑ\82алог Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80иÑ\80ованиÑ\8f';
 $string['availablelangs'] = 'Доступные языковые пакеты';
 $string['chooselanguagehead'] = 'Выберите язык';
 $string['chooselanguagesub'] = 'Сейчас необходимо выбрать язык ТОЛЬКО для сообщений во время установки. Язык сайта и пользовательских интерфейсов можно будет указать далее в процессе установки.';
-$string['clialreadyconfigured'] = 'Файл config.php уже существует. Если Вы хотите установить этот сайт, используйте admin/cli/install_database.php.';
-$string['clialreadyinstalled'] = 'Файл config.php уже существует. Если Вы хотите обновить сайт, то используйте скрипт admin/cli/upgrade.php.';
+$string['clialreadyconfigured'] = 'Файл config.php уже существует. Если Вы хотите установить Moodle на этот сайт, используйте admin/cli/install_database.php.';
+$string['clialreadyinstalled'] = 'Файл config.php уже существует. Если Вы хотите обновить сайт Moodle, то используйте скрипт admin/cli/upgrade.php.';
 $string['cliinstallheader'] = 'Программа установки Moodle {$a} в режиме командной строки';
 $string['databasehost'] = 'Сервер баз данных';
 $string['databasename'] = 'Название базы данных';
@@ -45,7 +45,7 @@ $string['datarootpermission'] =