Merge branch 'MDL-44990-master' of git://github.com/lameze/moodle
authorDan Poltawski <dan@moodle.com>
Fri, 18 Apr 2014 02:26:38 +0000 (10:26 +0800)
committerDan Poltawski <dan@moodle.com>
Fri, 18 Apr 2014 02:26:38 +0000 (10:26 +0800)
96 files changed:
availability/classes/frontend.php
availability/classes/info.php
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js
availability/yui/src/form/js/form.js
backup/util/ui/tests/behat/behat_backup.php
lib/alfresco/README_MOODLE.txt
lib/alfresco/Service/WebService/AlfrescoWebService.php
lib/behat/behat_field_manager.php
lib/behat/classes/behat_context_helper.php [new file with mode: 0644]
lib/behat/classes/behat_selectors.php
lib/behat/form_field/behat_form_field.php
lib/behat/form_field/behat_form_filemanager.php [new file with mode: 0644]
lib/db/install.xml
lib/db/upgrade.php
lib/outputrenderers.php
lib/tests/behat/behat_forms.php
lib/tests/behat/behat_hooks.php
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/notification/js/exception.js
mod/assign/classes/event/all_submissions_downloaded.php
mod/assign/classes/event/assessable_submitted.php
mod/assign/classes/event/base.php [new file with mode: 0644]
mod/assign/classes/event/batch_set_marker_allocation_viewed.php [new file with mode: 0644]
mod/assign/classes/event/batch_set_workflow_state_viewed.php [new file with mode: 0644]
mod/assign/classes/event/course_module_instance_list_viewed.php [new file with mode: 0644]
mod/assign/classes/event/extension_granted.php
mod/assign/classes/event/feedback_updated.php [new file with mode: 0644]
mod/assign/classes/event/feedback_viewed.php [new file with mode: 0644]
mod/assign/classes/event/grading_form_viewed.php [new file with mode: 0644]
mod/assign/classes/event/grading_table_viewed.php [new file with mode: 0644]
mod/assign/classes/event/identities_revealed.php
mod/assign/classes/event/marker_updated.php
mod/assign/classes/event/reveal_identities_confirmation_page_viewed.php [new file with mode: 0644]
mod/assign/classes/event/statement_accepted.php
mod/assign/classes/event/submission_confirmation_form_viewed.php [new file with mode: 0644]
mod/assign/classes/event/submission_created.php
mod/assign/classes/event/submission_duplicated.php
mod/assign/classes/event/submission_form_viewed.php [new file with mode: 0644]
mod/assign/classes/event/submission_graded.php
mod/assign/classes/event/submission_locked.php
mod/assign/classes/event/submission_status_updated.php
mod/assign/classes/event/submission_status_viewed.php [new file with mode: 0644]
mod/assign/classes/event/submission_unlocked.php
mod/assign/classes/event/submission_updated.php
mod/assign/classes/event/submission_viewed.php [new file with mode: 0644]
mod/assign/classes/event/workflow_state_updated.php
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js
mod/assign/feedback/editpdf/yui/src/editor/js/editor.js
mod/assign/feedback/offline/locallib.php
mod/assign/index.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/submission/file/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/tests/base_test.php
mod/assign/tests/event_test.php [deleted file]
mod/assign/tests/events_test.php [new file with mode: 0644]
mod/assign/tests/fixtures/event_mod_assign_fixtures.php
mod/assign/tests/locallib_test.php
mod/book/classes/event/chapter_created.php
mod/book/classes/event/chapter_deleted.php
mod/book/classes/event/chapter_updated.php
mod/book/classes/event/chapter_viewed.php
mod/book/classes/event/course_module_instance_list_viewed.php
mod/book/classes/event/course_module_viewed.php
mod/book/delete.php
mod/book/edit.php
mod/book/index.php
mod/book/move.php
mod/book/show.php
mod/book/tests/events_test.php
mod/book/tool/exportimscp/classes/event/book_exported.php
mod/book/tool/exportimscp/index.php
mod/book/tool/exportimscp/tests/events_test.php
mod/book/tool/importhtml/locallib.php
mod/book/tool/print/classes/event/book_printed.php
mod/book/tool/print/classes/event/chapter_printed.php
mod/book/tool/print/index.php
mod/book/tool/print/tests/events_test.php
mod/book/upgrade.txt [new file with mode: 0644]
mod/book/view.php
mod/forum/tests/behat/add_forum.feature
report/log/classes/table_log.php
report/log/locallib.php
repository/alfresco/lang/en/repository_alfresco.php
repository/tests/behat/behat_filepicker.php
repository/upload/tests/behat/behat_repository_upload.php
user/profile/definelib.php
user/profile/index.php
version.php

index f2a7276..ea7b012 100644 (file)
@@ -172,7 +172,7 @@ abstract class frontend {
         $decoded = json_decode($data['availabilityconditionsjson']);
         if (!$decoded) {
             // This shouldn't be possible.
-            throw new coding_exception('Invalid JSON from availabilityconditionsjson field');
+            throw new \coding_exception('Invalid JSON from availabilityconditionsjson field');
         }
         if (!empty($decoded->errors)) {
             $error = '';
index 965e552..a335d38 100644 (file)
@@ -193,12 +193,7 @@ abstract class info {
             $tree = $this->get_availability_tree();
             $result = $tree->check_available(false, $this, $grabthelot, $userid);
         } catch (\coding_exception $e) {
-            // We catch the message because it causes fatal problems in most of
-            // the GUI if this exception gets thrown (you can't edit the
-            // activity to fix it). Obviously it should never happen anyway, but
-            // just in case.
-            debugging('Error processing availability data for &lsquo;' .
-                    $this->get_thing_name() . '&rsquo;: ' . s($e->a), DEBUG_DEVELOPER);
+            $this->warn_about_invalid_availability($e);
             $this->modinfo = null;
             return false;
         }
@@ -237,7 +232,12 @@ abstract class info {
         if (is_null($this->availability)) {
             return true;
         } else {
-            return $this->get_availability_tree()->is_available_for_all();
+            try {
+                return $this->get_availability_tree()->is_available_for_all();
+            } catch (\coding_exception $e) {
+                $this->warn_about_invalid_availability($e);
+                return false;
+            }
         }
     }
 
@@ -273,13 +273,32 @@ abstract class info {
             $this->modinfo = null;
             return $result;
         } catch (\coding_exception $e) {
-            // Again we catch the message to avoid problems in GUI.
-            debugging('Error processing availability data for &lsquo;' .
-                    $this->get_thing_name() . '&rsquo;: ' . s($e->a), DEBUG_DEVELOPER);
+            $this->warn_about_invalid_availability($e);
             return false;
         }
     }
 
+    /**
+     * In some places we catch coding_exception because if a bug happens, it
+     * would be fatal for the course page GUI; instead we just show a developer
+     * debug message.
+     *
+     * @param \coding_exception $e Exception that occurred
+     */
+    protected function warn_about_invalid_availability(\coding_exception $e) {
+        $name = $this->get_thing_name();
+        // If it occurs while building modinfo based on somebody calling $cm->name,
+        // we can't get $cm->name, and this line will cause a warning.
+        $htmlname = @$this->format_info($name, $this->course);
+        if ($htmlname === '') {
+            // So instead use the numbers (cmid) from the tag.
+            $htmlname = preg_replace('~[^0-9]~', '', $name);
+        }
+        $info = 'Error processing availability data for &lsquo;' . $htmlname
+                 . '&rsquo;: ' . s($e->a);
+        debugging($info, DEBUG_DEVELOPER);
+    }
+
     /**
      * Called during restore (near end of restore). Updates any necessary ids
      * and writes the updated tree to the database. May output warnings if
index 4fec1b2..229f79a 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js differ
index aeb5c1e..60ede80 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js differ
index 4fec1b2..229f79a 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js differ
index 051c2c9..85fc922 100644 (file)
@@ -94,12 +94,16 @@ M.core_availability.form = {
 
         // Get top-level tree as JSON.
         var value = this.field.get('value');
-        if (value === '') {
-            this.rootList = new M.core_availability.List(null, true);
-        } else {
-            var data = Y.JSON.parse(value);
-            this.rootList = new M.core_availability.List(data, true);
+        var data = null;
+        if (value !== '') {
+            try {
+                data = Y.JSON.parse(value);
+            } catch(x) {
+                // If the JSON data is not valid, treat it as empty.
+                this.field.set('value', '');
+            }
         }
+        this.rootList = new M.core_availability.List(data, true);
         this.mainDiv.appendChild(this.rootList.node);
 
         // Update JSON value after loading (to reflect any changes that need
index 463f278..21f82f8 100644 (file)
@@ -349,9 +349,7 @@ class behat_backup extends behat_base {
         foreach ($datahash as $locator => $value) {
 
             try {
-                // Using $this->find* to enforce stability over speed.
-                $fieldnode = $this->find_field($locator);
-                $field = behat_field_manager::get_form_field($fieldnode, $this->getSession());
+                $field = behat_field_manager::get_form_field_from_label($locator, $this);
                 $field->set_value($value);
 
             } catch (ElementNotFoundException $e) {
index 83179f0..aaf6400 100644 (file)
@@ -34,6 +34,8 @@
     - AlfrescoWebService::__soapCall() arguments do not match SoapClient::__soapCall()
     - AlfrescoWebService::__doRequest() arguments do not match SoapClient::__soapCall()
 
+6. Apply the changes from MDL-41975 in regard with the timestamp
+
 == Alfresco PHP Library ==
 
 Installation and developer documentation for the Alfresco PHP Library can be found on the Alfresco Wiki.
index b549755..898dcdf 100644 (file)
@@ -79,8 +79,8 @@ class AlfrescoWebService extends SoapClient
 \r
          // Construct Timestamp Header\r
          $timeStamp = $dom->createElementNS($this->wsUtilityNS, "Timestamp");\r
-         $createdDate = date("Y-m-d\TH:i:s\Z", mktime(date("H")+24, date("i"), date("s"), date("m"), date("d"), date("Y")));\r
-         $expiresDate = date("Y-m-d\TH:i:s\Z", mktime(date("H")+25, date("i"), date("s"), date("m"), date("d"), date("Y")));\r
+         $createdDate = gmdate("Y-m-d\TH:i:s\Z", gmmktime(gmdate("H"), gmdate("i"), gmdate("s"), gmdate("m"), gmdate("d"), gmdate("Y")));\r
+         $expiresDate = gmdate("Y-m-d\TH:i:s\Z", gmmktime(gmdate("H")+1, gmdate("i"), gmdate("s"), gmdate("m"), gmdate("d"), gmdate("Y")));\r
          $created = new DOMElement("Created", $createdDate, $this->wsUtilityNS);\r
          $expires = new DOMElement("Expires", $expiresDate, $this->wsUtilityNS);\r
          $timeStamp->appendChild($created);\r
index 6bbc39e..d2e8c7f 100644 (file)
@@ -26,7 +26,9 @@
 // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
 
 use Behat\Mink\Session as Session,
-    Behat\Mink\Element\NodeElement as NodeElement;
+    Behat\Mink\Element\NodeElement as NodeElement,
+    Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
+    Behat\MinkExtension\Context\RawMinkContext as RawMinkContext;
 
 /**
  * Helper to interact with form fields.
@@ -38,6 +40,30 @@ use Behat\Mink\Session as Session,
  */
 class behat_field_manager {
 
+    /**
+     * Gets an instance of the form field from it's label
+     *
+     * @param string $label
+     * @param RawMinkContext $context
+     * @return behat_form_field
+     */
+    public static function get_form_field_from_label($label, RawMinkContext $context) {
+
+        // There are moodle form elements that are not directly related with
+        // a basic HTML form field, we should also take care of them.
+        try {
+            // The DOM node.
+            $fieldnode = $context->find_field($label);
+        } catch (ElementNotFoundException $e) {
+
+            // Looking for labels that points to filemanagers.
+            $fieldnode = $context->find_filemanager($label);
+        }
+
+        // The behat field manager.
+        return self::get_form_field($fieldnode, $context->getSession());
+    }
+
     /**
      * Gets an instance of the form field.
      *
@@ -217,6 +243,7 @@ class behat_field_manager {
      * @todo MDL-XXXXX This will be deleted in Moodle 2.8
      * @see behat_field_manager::get_form_field()
      * @param NodeElement $fieldnode
+     * @param string $locator
      * @param Session $session The behat browser session
      * @return behat_form_field
      */
@@ -237,6 +264,7 @@ class behat_field_manager {
      * @todo MDL-XXXXX This will be deleted in Moodle 2.8
      * @see behat_field_manager::get_field_node_type()
      * @param NodeElement $fieldnode The current node.
+     * @param string $locator
      * @param Session $session The behat browser session
      * @return mixed A NodeElement if we continue looking for the element type and String or false when we are done.
      */
diff --git a/lib/behat/classes/behat_context_helper.php b/lib/behat/classes/behat_context_helper.php
new file mode 100644 (file)
index 0000000..cdeea57
--- /dev/null
@@ -0,0 +1,111 @@
+<?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/>.
+
+/**
+ * Helper to initialise behat contexts from moodle code.
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+use Behat\Mink\Session as Session,
+    Behat\Mink\Mink as Mink;
+
+/**
+ * Helper to get behat contexts.
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_context_helper {
+
+    /**
+     * List of already initialized contexts.
+     *
+     * @var array
+     */
+    protected static $contexts = array();
+
+    /**
+     * @var Mink.
+     */
+    protected static $mink = false;
+
+    /**
+     * Sets the browser session.
+     *
+     * @param Session $session
+     * @return void
+     */
+    public static function set_session(Session $session) {
+
+        // Set mink to be able to init a context.
+        self::$mink = new Mink(array('mink' => $session));
+        self::$mink->setDefaultSessionName('mink');
+    }
+
+    /**
+     * Gets the required context.
+     *
+     * Getting a context you get access to all the steps
+     * that uses direct API calls; steps returning step chains
+     * can not be executed like this.
+     *
+     * @throws coding_exception
+     * @param string $classname Context identifier (the class name).
+     * @return behat_base
+     */
+    public static function get($classname) {
+
+        if (!self::init_context($classname)) {
+            throw coding_exception('The required "' . $classname . '" class does not exist');
+        }
+
+        return self::$contexts[$classname];
+    }
+
+    /**
+     * Initializes the required context.
+     *
+     * @throws coding_exception
+     * @param string $classname
+     * @return bool
+     */
+    protected static function init_context($classname) {
+
+        if (!empty(self::$contexts[$classname])) {
+            return true;
+        }
+
+        if (!class_exists($classname)) {
+            return false;
+        }
+
+        $instance = new $classname();
+        $instance->setMink(self::$mink);
+
+        self::$contexts[$classname] = $instance;
+
+        return true;
+    }
+
+}
index a46930e..ddacab4 100644 (file)
@@ -64,6 +64,7 @@ class behat_selectors {
         'checkbox' => 'checkbox',
         'radio' => 'radio',
         'file' => 'file',
+        'filemanager' => 'filemanager',
         'optgroup' => 'optgroup',
         'option' => 'option',
         'table' => 'table',
@@ -102,6 +103,9 @@ XPATH
 XPATH
         , 'table_row' => <<<XPATH
 .//tr[contains(normalize-space(.), %locator%)]
+XPATH
+        , 'filemanager' => <<<XPATH
+//div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ')]/descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
 XPATH
     );
 
index 4d3f1b4..c1abb1a 100644 (file)
@@ -50,6 +50,12 @@ class behat_form_field {
      */
     protected $field;
 
+    /**
+     * @var string The field's locator.
+     */
+    protected $fieldlocator = false;
+
+
     /**
      * General constructor with the node and the session to interact with.
      *
@@ -171,4 +177,63 @@ class behat_form_field {
         }
         return true;
     }
+
+    /**
+     * Gets the field locator.
+     *
+     * Defaults to the field label but you can
+     * specify other locators if you are interested.
+     *
+     * Public visibility as in most cases will be hard to
+     * use this method in a generic way, as fields can
+     * be selected using multiple ways (label, id, name...).
+     *
+     * @throws coding_exception
+     * @param string $locatortype
+     * @return string
+     */
+    protected function get_field_locator($locatortype = false) {
+
+        if (!empty($this->fieldlocator)) {
+            return $this->fieldlocator;
+        }
+
+        $fieldid = $this->field->getAttribute('id');
+
+        // Defaults to label.
+        if ($locatortype == 'label' || $locatortype == false) {
+
+            $labelnode = $this->session->getPage()->find('xpath', '//label[@for="' . $fieldid . '"]');
+
+            // Exception only if $locatortype was specified.
+            if (!$labelnode && $locatortype == 'label') {
+                throw new coding_exception('Field with "' . $fieldid . '" id does not have a label.');
+            }
+
+            $this->fieldlocator = $labelnode->getText();
+        }
+
+        // Let's look for the name as a second option (more popular than
+        // id's when pointing to fields).
+        if (($locatortype == 'name' || $locatortype == false) &&
+                empty($this->fieldlocator)) {
+
+            $name = $this->field->getAttribute('name');
+
+            // Exception only if $locatortype was specified.
+            if (!$name && $locatortype == 'name') {
+                throw new coding_exception('Field with "' . $fieldid . '" id does not have a name attribute.');
+            }
+
+            $this->fieldlocator = $name;
+        }
+
+        // Otherwise returns the id if no specific locator type was provided.
+        if (empty($this->fieldlocator)) {
+            $this->fieldlocator = $fieldid;
+        }
+
+        return $this->fieldlocator;
+    }
+
 }
diff --git a/lib/behat/form_field/behat_form_filemanager.php b/lib/behat/form_field/behat_form_filemanager.php
new file mode 100644 (file)
index 0000000..055efbf
--- /dev/null
@@ -0,0 +1,122 @@
+<?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 manager form element.
+ *
+ * @package    core_form
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__  . '/behat_form_field.php');
+
+/**
+ * File manager form field.
+ *
+ * Simple filemanager field manager to allow
+ * forms to be filled using TableNodes. It only
+ * adds files and checks the field contents in the
+ * root directory. If you want to run complex actions
+ * that involves subdirectories or other repositories
+ * than 'Upload a file' you should use steps related with
+ * behat_filepicker::i_add_file_from_repository_to_filemanager
+ * this is intended to be used with multi-field
+ *
+ * This field manager allows you to:
+ * - Get: A comma-separated list of the root directory
+ *   file names, including folders.
+ * - Set: Add a file, in case you want to add more than
+ *     one file you can always set two table rows using
+ *     the same locator.
+ * - Match: A comma-separated list of file names.
+ *
+ * @package    core_form
+ * @category   test
+ * @copyright  2014 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_form_filemanager extends behat_form_field {
+
+    /**
+     * Gets the value.
+     *
+     * @return string A comma-separated list of the root directory file names.
+     */
+    public function get_value() {
+
+        // Wait until DOM and JS is ready.
+        $this->session->wait(behat_base::TIMEOUT, behat_base::PAGE_READY_JS);
+
+        // Get the label to restrict the files to this single form field.
+        $fieldlabel = $this->get_field_locator();
+
+        // Get the name of the current directory elements.
+        $xpath = "//label[contains(., '" . $fieldlabel . "')]" .
+            "/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' fitemtitle ')]" .
+            "/following-sibling::div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ')]" .
+            "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-filename ')]";
+
+        // We don't need to wait here, also we don't have access to protected
+        // contexts find* methods.
+        $files = $this->session->getPage()->findAll('xpath', $xpath);
+
+        if (!$files) {
+            return '';
+        }
+
+        $filenames = array();
+        foreach ($files as $filenode) {
+            $filenames[] = $filenode->getText();
+        }
+
+        return implode(',', $filenames);
+    }
+
+    /**
+     * Sets the field value.
+     *
+     * @param string $value
+     * @return void
+     */
+    public function set_value($value) {
+
+        // Getting the filemanager label from the DOM.
+        $fieldlabel = $this->get_field_locator();
+
+        // Getting the filepicker context and using the step definition
+        // to upload the requested file.
+        $uploadcontext = behat_context_helper::get('behat_repository_upload');
+        $uploadcontext->i_upload_file_to_filemanager($value, $fieldlabel);
+    }
+
+    /**
+     * Matches the provided filename/s against the current field value.
+     *
+     * If the filemanager contains more than one file the $expectedvalue
+     * value should include all the file names separating them by comma.
+     *
+     * @param string $expectedvalue
+     * @return bool The provided value matches the field value?
+     */
+    public function matches($expectedvalue) {
+        return $this->text_matches($expectedvalue);
+    }
+
+}
index f47c8ce..518e851 100644 (file)
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
       <INDEXES>
-        <INDEX NAME="userfieldidx" UNIQUE="false" FIELDS="userid, fieldid"/>
+        <INDEX NAME="userfieldidx" UNIQUE="true" FIELDS="userid, fieldid"/>
       </INDEXES>
     </TABLE>
     <TABLE NAME="question_categories" COMMENT="Categories are for grouping questions">
index d753199..4443c9b 100644 (file)
@@ -3592,5 +3592,37 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2014040800.00);
     }
 
+    if ($oldversion < 2014041500.01) {
+
+        $table = new xmldb_table('user_info_data');
+
+        $sql = 'SELECT DISTINCT info.id
+                  FROM {user_info_data} info
+            INNER JOIN {user_info_data} older
+                    ON info.fieldid = older.fieldid
+                   AND info.userid = older.userid
+                   AND older.id < info.id';
+        $transaction = $DB->start_delegated_transaction();
+        $rs = $DB->get_recordset_sql($sql);
+        foreach ($rs as $rec) {
+            $DB->delete_records('user_info_data', array('id' => $rec->id));
+        }
+        $transaction->allow_commit();
+
+        $oldindex = new xmldb_index('userid_fieldid', XMLDB_INDEX_NOTUNIQUE, array('userid', 'fieldid'));
+        if ($dbman->index_exists($table, $oldindex)) {
+            $dbman->drop_index($table, $oldindex);
+        }
+
+        $newindex = new xmldb_index('userid_fieldid', XMLDB_INDEX_UNIQUE, array('userid', 'fieldid'));
+
+        if (!$dbman->index_exists($table, $newindex)) {
+            $dbman->add_index($table, $newindex);
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2014041500.01);
+    }
+
     return true;
 }
index e1795bd..343d379 100644 (file)
@@ -3514,7 +3514,10 @@ class core_renderer_ajax extends core_renderer {
         $e->debuginfo  = NULL;
         $e->reproductionlink = NULL;
         if (!empty($CFG->debug) and $CFG->debug >= DEBUG_DEVELOPER) {
-            $e->reproductionlink = $link;
+            $link = (string) $link;
+            if ($link) {
+                $e->reproductionlink = $link;
+            }
             if (!empty($debuginfo)) {
                 $e->debuginfo = $debuginfo;
             }
index 127b74f..b686efb 100644 (file)
@@ -166,10 +166,8 @@ class behat_forms extends behat_base {
      */
     public function the_field_matches_value($field, $value) {
 
-        $fieldnode = $this->find_field($field);
-
         // Get the field.
-        $formfield = behat_field_manager::get_form_field($fieldnode, $this->getSession());
+        $formfield = behat_field_manager::get_form_field_from_label($field, $this);
 
         // Checks if the provided value matches the current field value.
         if (!$formfield->matches($value)) {
@@ -193,10 +191,8 @@ class behat_forms extends behat_base {
      */
     public function the_field_does_not_match_value($field, $value) {
 
-        $fieldnode = $this->find_field($field);
-
         // Get the field.
-        $formfield = behat_field_manager::get_form_field($fieldnode, $this->getSession());
+        $formfield = behat_field_manager::get_form_field_from_label($field, $this);
 
         // Checks if the provided value matches the current field value.
         if ($formfield->matches($value)) {
@@ -348,11 +344,9 @@ class behat_forms extends behat_base {
      */
     protected function set_field_value($fieldlocator, $value) {
 
-        $node = $this->find_field($fieldlocator);
-
         // We delegate to behat_form_field class, it will
         // guess the type properly as it is a select tag.
-        $field = behat_field_manager::get_form_field($node, $this->getSession());
+        $field = behat_field_manager::get_form_field_from_label($fieldlocator, $this);
         $field->set_value($value);
     }
 
index 0f3d560..b6f0779 100644 (file)
@@ -110,6 +110,7 @@ class behat_hooks extends behat_base {
         // Now that we are MOODLE_INTERNAL.
         require_once(__DIR__ . '/../../behat/classes/behat_command.php');
         require_once(__DIR__ . '/../../behat/classes/behat_selectors.php');
+        require_once(__DIR__ . '/../../behat/classes/behat_context_helper.php');
         require_once(__DIR__ . '/../../behat/classes/util.php');
         require_once(__DIR__ . '/../../testing/classes/test_lock.php');
         require_once(__DIR__ . '/../../testing/classes/nasty_strings.php');
@@ -184,6 +185,7 @@ class behat_hooks extends behat_base {
         // We need the Mink session to do it and we do it only before the first scenario.
         if (self::is_first_scenario()) {
             behat_selectors::register_moodle_selectors($session);
+            behat_context_helper::set_session($session);
         }
 
         // Reset $SESSION.
index ad7ae33..9ca3e81 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js differ
index dd9e075..ba222b3 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js differ
index ad7ae33..9ca3e81 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js differ
index 618800a..482b861 100644 (file)
@@ -31,7 +31,7 @@ Y.extend(EXCEPTION, M.core.notification.info, {
             delay = this.get('hideTimeoutDelay');
         this.get(BASE).addClass('moodle-dialogue-exception');
         this.setStdModContent(Y.WidgetStdMod.HEADER,
-                '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + config.name + '</h1>', Y.WidgetStdMod.REPLACE);
+                '<h1 id="moodle-dialogue-'+config.COUNT+'-header-text">' + config.name + '</h1>', Y.WidgetStdMod.REPLACE);
         content = Y.Node.create('<div class="moodle-exception"></div>')
                 .append(Y.Node.create('<div class="moodle-exception-message">'+this.get('message')+'</div>'))
                 .append(Y.Node.create('<div class="moodle-exception-param hidden param-filename"><label>File:</label> ' +
index f1bc1d2..176c734 100644 (file)
@@ -34,14 +34,33 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class all_submissions_downloaded extends \core\event\base {
+class all_submissions_downloaded extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @return all_submissions_downloaded
      */
-    protected $legacylogdata;
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_graded $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,52 +71,47 @@ class all_submissions_downloaded extends \core\event\base {
         return "User {$this->userid} has downloaded all the submissions.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_all_submissions_downloaded', 'mod_assign');
+        return get_string('eventallsubmissionsdownloaded', 'mod_assign');
     }
 
     /**
-     * Get URL related to the action.
+     * Init method.
      *
-     * @return \moodle_url
+     * @return void
      */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+        $this->data['objecttable'] = 'assign';
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $this->set_legacy_logdata('download all submissions', get_string('downloadall', 'assign'));
+        return parent::get_legacy_logdata();
     }
 
     /**
-     * Init method.
+     * Custom validation.
      *
+     * @throws \coding_exception
      * @return void
      */
-    protected function init() {
-        $this->data['crud'] = 'r';
-        $this->data['edulevel'] = self::LEVEL_TEACHING;
-        $this->data['objecttable'] = 'assign';
-    }
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call all_submissions_downloaded::create() directly, use all_submissions_downloaded::create_from_assign() instead.');
+        }
 
+        parent::validate_data();
+    }
 }
index b639423..2ea5a23 100644 (file)
@@ -40,14 +40,36 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class assessable_submitted extends \core\event\assessable_submitted {
-
+class assessable_submitted extends base {
     /**
-     * Legacy log data.
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
      *
-     * @var array
+     * @param \assign $assign
+     * @param \stdClass $submission
+     * @param bool $editable
+     * @return assessable_submitted
      */
-    protected $legacylogdata;
+    public static function create_from_submission(\assign $assign, \stdClass $submission, $editable) {
+        global $USER;
+
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $submission->id,
+            'other' => array(
+                'submission_editable' => $editable,
+            ),
+        );
+        if (!empty($submission->userid) && ($submission->userid != $USER->id)) {
+            $data['relateduserid'] = $submission->userid;
+        }
+        /** @var assessable_submitted $event */
+        $event = self::create($data);
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_submission', $submission);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -83,51 +105,35 @@ class assessable_submitted extends \core\event\assessable_submitted {
         return 'assessable_submitted';
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_assessable_submitted', 'mod_assign');
+        return get_string('eventassessablesubmitted', 'mod_assign');
     }
 
     /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
-    }
-
-    /**
-     * Sets the legacy event log data.
+     * Init method.
      *
-     * @param \stdClass $legacylogdata legacy log data.
      * @return void
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function init() {
+        $this->data['objecttable'] = 'assign_submission';
+        $this->data['crud'] = 'u';
+        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
     }
 
     /**
-     * Init method.
+     * Return legacy data for add_to_log().
      *
-     * @return void
+     * @return array
      */
-    protected function init() {
-        parent::init();
-        $this->data['objecttable'] = 'assign_submission';
+    protected function get_legacy_logdata() {
+        $submission = $this->get_record_snapshot('assign_submission', $this->objectid);
+        $this->set_legacy_logdata('submit for grading', $this->assign->format_submission_for_log($submission));
+        return parent::get_legacy_logdata();
     }
 
     /**
@@ -138,6 +144,7 @@ class assessable_submitted extends \core\event\assessable_submitted {
      */
     protected function validate_data() {
         parent::validate_data();
+
         if (!isset($this->other['submission_editable'])) {
             throw new \coding_exception('Other must contain the key submission_editable.');
         }
diff --git a/mod/assign/classes/event/base.php b/mod/assign/classes/event/base.php
new file mode 100644 (file)
index 0000000..2dacf2e
--- /dev/null
@@ -0,0 +1,131 @@
+<?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/>.
+
+/**
+ * The mod_assign abstract base class.
+ *
+ * Most events can extend this class.
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+abstract class base extends \core\event\base {
+    /** @var \assign */
+    protected $assign;
+
+    /**
+     * Legacy log data.
+     *
+     * @var array
+     */
+    protected $legacylogdata;
+
+    /**
+     * Set assign instance for this event.
+     * @param \assign $assign
+     * @throws \coding_exception
+     */
+    public function set_assign(\assign $assign) {
+        if ($this->is_triggered()) {
+            throw new \coding_exception('set_assign() must be done before triggerring of event');
+        }
+        if ($assign->get_context()->id != $this->get_context()->id) {
+            throw new \coding_exception('Invalid assign isntance supplied!');
+        }
+        $this->assign = $assign;
+    }
+
+    /**
+     * Get assign instance.
+     *
+     * NOTE: to be used from observers only.
+     *
+     * @return \assign
+     */
+    public function get_assign() {
+        if ($this->is_restored()) {
+            throw new \coding_exception('get_assign() is intended for event observers only');
+        }
+        if (!isset($this->assign)) {
+            debugging('assign property should be initialised in each event', DEBUG_DEVELOPER);
+            global $CFG;
+            require_once($CFG->dirroot . '/mod/assign/locallib.php');
+            $cm = get_coursemodule_from_id('assign', $this->contextinstanceid, 0, false, MUST_EXIST);
+            $course = get_course($cm->course);
+            $this->assign = new \assign($this->get_context(), $cm, $course);
+        }
+        return $this->assign;
+    }
+
+
+    /**
+     * Returns relevant URL.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+    }
+
+    /**
+     * Sets the legacy event log data.
+     *
+     * @param string $action The current action
+     * @param string $info A detailed description of the change. But no more than 255 characters.
+     * @param string $url The url to the assign module instance.
+     */
+    public function set_legacy_logdata($action = '', $info = '', $url = '') {
+        $fullurl = 'view.php?id=' . $this->contextinstanceid;
+        if ($url != '') {
+            $fullurl .= '&' . $url;
+        }
+
+        $this->legacylogdata = array($this->courseid, 'assign', $action, $fullurl, $info, $this->contextinstanceid);
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        if (isset($this->legacylogdata)) {
+            return $this->legacylogdata;
+        }
+
+        return null;
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        parent::validate_data();
+
+        if ($this->contextlevel != CONTEXT_MODULE) {
+            throw new \coding_exception('Context passed must be module context.');
+        }
+    }
+}
diff --git a/mod/assign/classes/event/batch_set_marker_allocation_viewed.php b/mod/assign/classes/event/batch_set_marker_allocation_viewed.php
new file mode 100644 (file)
index 0000000..e4e2ca0
--- /dev/null
@@ -0,0 +1,126 @@
+<?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/>.
+
+/**
+ * The mod_assign batch set marker allocation viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign batch set marker allocation viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class batch_set_marker_allocation_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @return batch_set_marker_allocation_viewed
+     */
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var batch_set_marker_allocation_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventbatchsetmarkerallocationviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the batch set marker allocation for the assignment with the id
+            {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $logmessage = get_string('viewbatchmarkingallocation', 'assign');
+        $this->set_legacy_logdata('view batch set marker allocation', $logmessage);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call batch_set_marker_allocation_viewed::create() directly, use batch_set_marker_allocation_viewed::create_from_assign() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
diff --git a/mod/assign/classes/event/batch_set_workflow_state_viewed.php b/mod/assign/classes/event/batch_set_workflow_state_viewed.php
new file mode 100644 (file)
index 0000000..8353cb7
--- /dev/null
@@ -0,0 +1,125 @@
+<?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/>.
+
+/**
+ * The mod_assign assignment batch set workflow stated viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign assignment batch set workflow stated viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class batch_set_workflow_state_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @return batch_set_workflow_state_viewed
+     */
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var batch_set_workflow_state_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventbatchsetworkflowstateviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the batch set workflow for the assignment with the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $logmessage = get_string('viewbatchsetmarkingworkflowstate', 'assign');
+        $this->set_legacy_logdata('view batch set marking workflow state', $logmessage);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call batch_set_workflow_state_viewed::create() directly, use batch_set_workflow_state_viewed::create_from_assign() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
diff --git a/mod/assign/classes/event/course_module_instance_list_viewed.php b/mod/assign/classes/event/course_module_instance_list_viewed.php
new file mode 100644 (file)
index 0000000..71bfc3d
--- /dev/null
@@ -0,0 +1,52 @@
+<?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/>.
+
+/**
+ * The mod_assign instance list viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign instance list viewed event.
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
+    /**
+     * Create the event from course record.
+     *
+     * @param \stdClass $course
+     * @return course_module_instance_list_viewed
+     */
+    public static function create_from_course(\stdClass $course) {
+        $params = array(
+            'context' => \context_course::instance($course->id)
+        );
+        $event = \mod_assign\event\course_module_instance_list_viewed::create($params);
+        $event->add_record_snapshot('course', $course);
+        return $event;
+    }
+}
index 3b26e51..7210060 100644 (file)
@@ -34,14 +34,35 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class extension_granted extends \core\event\base {
+class extension_granted extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
      *
-     * @var array
+     * @param \assign $assign
+     * @param int $userid
+     * @return extension_granted
      */
-    protected $legacylogdata;
+    public static function create_from_assign(\assign $assign, $userid) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id,
+            'relateduserid' => $userid,
+        );
+        self::$preventcreatecall = false;
+        /** @var extension_granted $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +73,13 @@ class extension_granted extends \core\event\base {
         return "User {$this->userid} has granted an extension to {$this->relateduserid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_extension_granted', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventextensiongranted', 'mod_assign');
     }
 
     /**
@@ -91,13 +94,13 @@ class extension_granted extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $this->set_legacy_logdata('grant extension', $this->relateduserid);
+        return parent::get_legacy_logdata();
     }
 
     /**
@@ -107,7 +110,12 @@ class extension_granted extends \core\event\base {
      * @return void
      */
     protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call extension_granted::create() directly, use extension_granted::create_from_assign() instead.');
+        }
+
         parent::validate_data();
+
         if (!isset($this->relateduserid)) {
             throw new \coding_exception('relateduserid is a mandatory property.');
         }
diff --git a/mod/assign/classes/event/feedback_updated.php b/mod/assign/classes/event/feedback_updated.php
new file mode 100644 (file)
index 0000000..2bab6fe
--- /dev/null
@@ -0,0 +1,110 @@
+<?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/>.
+
+/**
+ * The mod_assign feedback updated event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign feedback updated event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class feedback_updated extends base {
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @param \stdClass $grade
+     * @return feedback_updated
+     */
+    public static function create_from_grade(\assign $assign, \stdClass $grade) {
+        $data = array(
+            'objectid' => $grade->id,
+            'relateduserid' => $grade->userid,
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        /** @var feedback_updated $event */
+        $event = self::create($data);
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_grades', $grade);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventfeedbackupdated', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} updated the feedback for the user with the id {$this->relateduserid}
+            for the assignment with the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        parent::validate_data();
+
+        if (!isset($this->relateduserid)) {
+            throw new \coding_exception('The \'relateduserid\' must be set.');
+        }
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
diff --git a/mod/assign/classes/event/feedback_viewed.php b/mod/assign/classes/event/feedback_viewed.php
new file mode 100644 (file)
index 0000000..18fdec3
--- /dev/null
@@ -0,0 +1,122 @@
+<?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/>.
+
+/**
+ * The mod_assign feedback viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign feedback viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class feedback_viewed extends base {
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @param \stdClass $grade
+     * @return feedback_viewed
+     */
+    public static function create_from_grade(\assign $assign, \stdClass $grade) {
+        $data = array(
+            'objectid' => $grade->id,
+            'relateduserid' => $grade->userid,
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        /** @var feedback_viewed $event */
+        $event = self::create($data);
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_grades', $grade);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'assign_grades';
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventfeedbackviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the feedback for the user with the id {$this->relateduserid}
+            for the assignment with the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $logmessage = get_string('viewfeedbackforuser', 'assign', $this->relateduserid);
+        $this->set_legacy_logdata('view feedback', $logmessage);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        parent::validate_data();
+
+        if (!isset($this->relateduserid)) {
+            throw new \coding_exception('The \'relateduserid\' must be set.');
+        }
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
diff --git a/mod/assign/classes/event/grading_form_viewed.php b/mod/assign/classes/event/grading_form_viewed.php
new file mode 100644 (file)
index 0000000..337b34a
--- /dev/null
@@ -0,0 +1,134 @@
+<?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/>.
+
+/**
+ * The mod_assign grading form viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign grading form viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class grading_form_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @param \stdClass $user
+     * @return grading_form_viewed
+     */
+    public static function create_from_user(\assign $assign, \stdClass $user) {
+        $data = array(
+            'relateduserid' => $user->id,
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var grading_form_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('user', $user);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventgradingformviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the grading form for the user with the id {$this->relateduserid}
+            for the assignment with the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $user = $this->get_record_snapshot('user', $this->relateduserid);
+        $msg = get_string('viewgradingformforstudent', 'assign',
+            array('id' => $user->id, 'fullname' => fullname($user)));
+        $this->set_legacy_logdata('view grading form', $msg);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call grading_form_viewed::create() directly, use grading_form_viewed::create_from_user() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->relateduserid)) {
+            throw new \coding_exception('The \'relateduserid\' must be set.');
+        }
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
diff --git a/mod/assign/classes/event/grading_table_viewed.php b/mod/assign/classes/event/grading_table_viewed.php
new file mode 100644 (file)
index 0000000..76b3848
--- /dev/null
@@ -0,0 +1,125 @@
+<?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/>.
+
+/**
+ * The mod_assign grading table viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign grading table viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class grading_table_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @return grading_table_viewed
+     */
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var grading_table_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventgradingtableviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the grading table for the assignment with the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $logmessage = get_string('viewsubmissiongradingtable', 'assign');
+        $this->set_legacy_logdata('view submission grading table', $logmessage);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call grading_table_viewed::create() directly, use grading_table_viewed::create_from_assign() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
index ad8948f..a724d9b 100644 (file)
@@ -34,14 +34,33 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class identities_revealed extends \core\event\base {
+class identities_revealed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @return identities_revealed
      */
-    protected $legacylogdata;
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id
+        );
+        self::$preventcreatecall = false;
+        /** @var identities_revealed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +71,13 @@ class identities_revealed extends \core\event\base {
         return "User {$this->userid} has revealed the identities in assignment {$this->objectid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_identities_revealed', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventidentitiesrevealed', 'mod_assign');
     }
 
     /**
@@ -91,13 +92,26 @@ class identities_revealed extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $this->set_legacy_logdata('reveal identities', get_string('revealidentities', 'assign'));
+        return parent::get_legacy_logdata();
     }
 
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call identities_revealed::create() directly, use identities_revealed::create_from_assign() instead.');
+        }
+
+        parent::validate_data();
+    }
 }
index 362fb3f..9a1eea6 100644 (file)
@@ -40,14 +40,41 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class marker_updated extends \core\event\base {
+class marker_updated extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @param \stdClass $user
+     * @param \stdClass $marker
+     * @return marker_updated
      */
-    protected $legacylogdata;
+    public static function create_from_marker(\assign $assign, \stdClass $user, \stdClass $marker) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id,
+            'relateduserid' => $user->id,
+            'other' => array(
+                'markerid' => $marker->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var marker_updated $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('user', $user);
+        $event->add_record_snapshot('user', $marker);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -58,31 +85,13 @@ class marker_updated extends \core\event\base {
         return "User {$this->userid} has set the marker of {$this->relateduserid} to {$this->other['markerid']}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_marker_updated', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventmarkerupdated', 'mod_assign');
     }
 
     /**
@@ -97,23 +106,31 @@ class marker_updated extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $user = $this->get_record_snapshot('user', $this->relateduserid);
+        $marker = $this->get_record_snapshot('user', $this->other['markerid']);
+        $a = array('id' => $user->id, 'fullname' => fullname($user), 'marker' => fullname($marker));
+        $logmessage = get_string('setmarkerallocationforlog', 'assign', $a);
+        $this->set_legacy_logdata('set marking allocation', $logmessage);
+        return parent::get_legacy_logdata();
     }
 
     /**
      * Custom validation.
      *
      * @throws \coding_exception
-     * @return void
      */
     protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call marker_updated::create() directly, use marker_updated::create_from_marker() instead.');
+        }
+
         parent::validate_data();
+
         if (!isset($this->other['markerid'])) {
             throw new \coding_exception('markerid must be set in $other.');
         } else if (!isset($this->relateduserid)) {
diff --git a/mod/assign/classes/event/reveal_identities_confirmation_page_viewed.php b/mod/assign/classes/event/reveal_identities_confirmation_page_viewed.php
new file mode 100644 (file)
index 0000000..5a788ea
--- /dev/null
@@ -0,0 +1,125 @@
+<?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/>.
+
+/**
+ * The mod_assign reveal identities confirmation page viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign reveal identities confirmation page viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class reveal_identities_confirmation_page_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @return reveal_identities_confirmation_page_viewed
+     */
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var reveal_identities_confirmation_page_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventrevealidentitiesconfirmationpageviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the confirmation page for revealing identities for the
+            assignment with the id {$this->other['assignid']}.";
+    }
+
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $this->set_legacy_logdata('view', get_string('viewrevealidentitiesconfirm', 'assign'));
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call reveal_identities_confirmation_page_viewed::create() directly, use reveal_identities_confirmation_page_viewed::create_from_grade() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
index d0a0811..f9b452f 100644 (file)
@@ -34,14 +34,35 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class statement_accepted extends \core\event\base {
+class statement_accepted extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @param \stdClass $submission
+     * @return statement_accepted
      */
-    protected $legacylogdata;
+    public static function create_from_submission(\assign $assign, \stdClass $submission) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $submission->id
+        );
+        self::$preventcreatecall = false;
+        /** @var statement_accepted $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_submission', $submission);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +73,13 @@ class statement_accepted extends \core\event\base {
         return "The user {$this->userid} has accepted the statement of the submission {$this->objectid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_statement_accepted', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action.
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventstatementaccepted', 'mod_assign');
     }
 
     /**
@@ -86,18 +89,33 @@ class statement_accepted extends \core\event\base {
      */
     protected function init() {
         $this->data['crud'] = 'r';
-        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
+        $this->data['edulevel'] = self::LEVEL_OTHER;
         $this->data['objecttable'] = 'assign_submission';
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        global $USER;
+        $logmessage = get_string('submissionstatementacceptedlog', 'mod_assign', fullname($USER)); // Nasty hack.
+        $this->set_legacy_logdata('submission statement accepted', $logmessage);
+        return parent::get_legacy_logdata();
     }
 
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call statement_accepted::create() directly, use statement_accepted::create_from_submission() instead.');
+        }
+
+        parent::validate_data();
+    }
 }
diff --git a/mod/assign/classes/event/submission_confirmation_form_viewed.php b/mod/assign/classes/event/submission_confirmation_form_viewed.php
new file mode 100644 (file)
index 0000000..15884d7
--- /dev/null
@@ -0,0 +1,126 @@
+<?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/>.
+
+/**
+ * The mod_assign submission form viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign submission form viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class submission_confirmation_form_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @return submission_confirmation_form_viewed
+     */
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_confirmation_form_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubmissionconfirmationformviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the submission confirmation form for the assignment with the id
+            {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $logmessage = get_string('viewownsubmissionform', 'assign');
+        $this->set_legacy_logdata('view confirm submit assignment form', $logmessage);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_confirmation_form_viewed::create() directly, use submission_confirmation_form_viewed::create_from_assign() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
index ad67856..af1c9e9 100644 (file)
@@ -41,7 +41,7 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2014 Adrian Greeve <adrian@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-abstract class submission_created extends \core\event\base {
+abstract class submission_created extends base {
 
     /**
      * Init method.
@@ -60,14 +60,6 @@ abstract class submission_created extends \core\event\base {
         return get_string('eventsubmissioncreated', 'mod_assign');
     }
 
-    /**
-     * Returns relevant URL.
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
-    }
-
     /**
      * Custom validation.
      *
index 04e4b1c..894ac48 100644 (file)
@@ -34,14 +34,35 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class submission_duplicated extends \core\event\base {
+class submission_duplicated extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @param \stdClass $submission
+     * @return submission_duplicated
      */
-    protected $legacylogdata;
+    public static function create_from_submission(\assign $assign, \stdClass $submission) {
+        $data = array(
+            'objectid' => $submission->id,
+            'context' => $assign->get_context(),
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_duplicated $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_submission', $submission);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +73,13 @@ class submission_duplicated extends \core\event\base {
         return "The user {$this->userid} duplicated his submission {$this->objectid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_submission_duplicated', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action.
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventsubmissionduplicated', 'mod_assign');
     }
 
     /**
@@ -91,13 +94,26 @@ class submission_duplicated extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $submission = $this->get_record_snapshot('assign_submission', $this->objectid);
+        $this->set_legacy_logdata('submissioncopied', $this->assign->format_submission_for_log($submission));
+        return parent::get_legacy_logdata();
     }
 
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_duplicated::create() directly, use submission_duplicated::create_from_submission() instead.');
+        }
+
+        parent::validate_data();
+    }
 }
diff --git a/mod/assign/classes/event/submission_form_viewed.php b/mod/assign/classes/event/submission_form_viewed.php
new file mode 100644 (file)
index 0000000..f2838aa
--- /dev/null
@@ -0,0 +1,142 @@
+<?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/>.
+
+/**
+ * The mod_assign submission form viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign submission form viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class submission_form_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @param \stdClass $user
+     * @return submission_form_viewed
+     */
+    public static function create_from_user(\assign $assign, \stdClass $user) {
+        $data = array(
+            'relateduserid' => $user->id,
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_form_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('user', $user);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubmissionformviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        if ($this->userid != $this->relateduserid) {
+            return "The user with the id {$this->userid} viewed the submission form for the user with the id {$this->relateduserid}
+                for the assignment with the id {$this->other['assignid']}.";
+        }
+
+        return "The user with the id {$this->userid} viewed their submission for the assignment with the id
+            {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        if ($this->relateduserid == $this->userid) {
+            $title = get_string('editsubmission', 'assign');
+        } else {
+            $user = $this->get_record_snapshot('user', $this->relateduserid);
+            $title = get_string('editsubmissionother', 'assign', fullname($user));
+        }
+        $this->set_legacy_logdata('view submit assignment form', $title);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_form_viewed::create() directly, use submission_form_viewed::create_from_user() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->relateduserid)) {
+            throw new \coding_exception('The \'relateduserid\' must be set.');
+        }
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
index 3ac1e46..5f04c83 100644 (file)
@@ -34,14 +34,36 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class submission_graded extends \core\event\base {
+class submission_graded extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
      *
-     * @var array
+     * @param \assign $assign
+     * @param \stdClass $grade
+     * @return submission_graded
      */
-    protected $legacylogdata;
+    public static function create_from_grade(\assign $assign, \stdClass $grade) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $grade->id,
+            'relateduserid' => $grade->userid
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_graded $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_grades', $grade);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +74,13 @@ class submission_graded extends \core\event\base {
         return "User {$this->userid} has graded the submission {$this->objectid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_submission_graded', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventsubmissiongraded', 'mod_assign');
     }
 
     /**
@@ -91,13 +95,14 @@ class submission_graded extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $grade = $this->get_record_snapshot('assign_grades', $this->objectid);
+        $this->set_legacy_logdata('grade submission', $this->assign->format_grade_for_log($grade));
+        return parent::get_legacy_logdata();
     }
 
     /**
@@ -107,7 +112,12 @@ class submission_graded extends \core\event\base {
      * @return void
      */
     protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_graded::create() directly, use submission_graded::create_from_grade() instead.');
+        }
+
         parent::validate_data();
+
         if (!isset($this->relateduserid)) {
             throw new \coding_exception('relateduserid is a mandatory property.');
         }
index 5275478..e5f16b7 100644 (file)
@@ -34,14 +34,36 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class submission_locked extends \core\event\base {
+class submission_locked extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @param \stdClass $user
+     * @return submission_locked
      */
-    protected $legacylogdata;
+    public static function create_from_user(\assign $assign, \stdClass $user) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id,
+            'relateduserid' => $user->id,
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_locked $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('user', $user);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +74,13 @@ class submission_locked extends \core\event\base {
         return "User {$this->userid} locked the submission for user {$this->relateduserid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_submission_locked', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventsubmissionlocked', 'mod_assign');
     }
 
     /**
@@ -91,23 +95,29 @@ class submission_locked extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $user = $this->get_record_snapshot('user', $this->relateduserid);
+        $logmessage = get_string('locksubmissionforstudent', 'assign', array('id' => $user->id, 'fullname' => fullname($user)));
+        $this->set_legacy_logdata('lock submission', $logmessage);
+        return parent::get_legacy_logdata();
     }
 
     /**
      * Custom validation.
      *
      * @throws \coding_exception
-     * @return void
      */
     protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_locked::create() directly, use submission_locked::create_from_user() instead.');
+        }
+
         parent::validate_data();
+
         if (!isset($this->relateduserid)) {
             throw new \coding_exception('relateduserid is a mandatory property.');
         }
index 6941310..4d1b207 100644 (file)
@@ -40,14 +40,31 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class submission_status_updated extends \core\event\base {
-
+class submission_status_updated extends base {
     /**
-     * Legacy log data.
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
      *
-     * @var array
+     * @param \assign $assign
+     * @param \stdClass $submission
+     * @return submission_status_updated
      */
-    protected $legacylogdata;
+    public static function create_from_submission(\assign $assign, \stdClass $submission) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $submission->id,
+            'relateduserid' => ($assign->get_instance()->teamsubmission) ? null : $submission->userid,
+            'other' => array(
+                'newstatus' => $submission->status
+            )
+        );
+        /** @var submission_status_updated $event */
+        $event = self::create($data);
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_submission', $submission);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -58,31 +75,13 @@ class submission_status_updated extends \core\event\base {
         return "User {$this->userid} has updated the status of the submission {$this->objectid} to {$this->other['newstatus']}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_submission_status_updated', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventsubmissionstatusupdated', 'mod_assign');
     }
 
     /**
@@ -97,23 +96,26 @@ class submission_status_updated extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $submission = $this->get_record_snapshot('assign_submission', $this->objectid);
+        $user = $this->get_record_snapshot('user', $submission->userid);
+        $logmessage = get_string('reverttodraftforstudent', 'assign', array('id' => $user->id, 'fullname' => fullname($user)));
+        $this->set_legacy_logdata('revert submission to draft', $logmessage);
+        return parent::get_legacy_logdata();
     }
 
     /**
      * Custom validation.
      *
      * @throws \coding_exception
-     * @return void
      */
     protected function validate_data() {
         parent::validate_data();
+
         if (!isset($this->other['newstatus'])) {
             throw new \coding_exception('newstatus must be set in $other.');
         }
diff --git a/mod/assign/classes/event/submission_status_viewed.php b/mod/assign/classes/event/submission_status_viewed.php
new file mode 100644 (file)
index 0000000..34d8d58
--- /dev/null
@@ -0,0 +1,127 @@
+<?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/>.
+
+/**
+ * The mod_assign submission status viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign submission status viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class submission_status_viewed extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
+
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @return submission_status_viewed
+     */
+    public static function create_from_assign(\assign $assign) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_status_viewed $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubmissionstatusviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} has viewed the status of their submission for the assignment with
+            the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $this->set_legacy_logdata('view', get_string('viewownsubmissionstatus', 'assign'));
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_status_viewed::create() directly, use submission_status_viewed::create_from_assign() instead.');
+        }
+
+        parent::validate_data();
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
index 5105e35..69198ac 100644 (file)
@@ -34,14 +34,36 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class submission_unlocked extends \core\event\base {
+class submission_unlocked extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @param \stdClass $user
+     * @return submission_unlocked
      */
-    protected $legacylogdata;
+    public static function create_from_user(\assign $assign, \stdClass $user) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id,
+            'relateduserid' => $user->id,
+        );
+        self::$preventcreatecall = false;
+        /** @var submission_unlocked $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('user', $user);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -52,31 +74,13 @@ class submission_unlocked extends \core\event\base {
         return "User {$this->userid} unlocked the submission for user {$this->relateduserid}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_submission_unlocked', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventsubmissionunlocked', 'mod_assign');
     }
 
     /**
@@ -91,23 +95,29 @@ class submission_unlocked extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $user = $this->get_record_snapshot('user', $this->relateduserid);
+        $logmessage = get_string('unlocksubmissionforstudent', 'assign', array('id' => $user->id, 'fullname' => fullname($user)));
+        $this->set_legacy_logdata('unlock submission', $logmessage);
+        return parent::get_legacy_logdata();
     }
 
     /**
      * Custom validation.
      *
      * @throws \coding_exception
-     * @return void
      */
     protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call submission_unlocked::create() directly, use submission_unlocked::create_from_user() instead.');
+        }
+
         parent::validate_data();
+
         if (!isset($this->relateduserid)) {
             throw new \coding_exception('relateduserid is a mandatory property.');
         }
index d2cebf4..8b22fd4 100644 (file)
@@ -41,7 +41,7 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-abstract class submission_updated extends \core\event\base {
+abstract class submission_updated extends base {
 
     /**
      * Init method.
@@ -60,14 +60,6 @@ abstract class submission_updated extends \core\event\base {
         return get_string('eventsubmissionupdated', 'mod_assign');
     }
 
-    /**
-     * Returns relevant URL.
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
-    }
-
     /**
      * Custom validation.
      *
diff --git a/mod/assign/classes/event/submission_viewed.php b/mod/assign/classes/event/submission_viewed.php
new file mode 100644 (file)
index 0000000..b197230
--- /dev/null
@@ -0,0 +1,122 @@
+<?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/>.
+
+/**
+ * The mod_assign submission viewed event.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_assign\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_assign submission viewed event.
+ *
+ * @property-read array $other {
+ *      Extra information about the event.
+ *
+ *      - int assignid: the id of the assignment.
+ * }
+ *
+ * @package    mod_assign
+ * @since      Moodle 2.7
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class submission_viewed extends base {
+    /**
+     * Create instance of event.
+     *
+     * @param \assign $assign
+     * @param \stdClass $submission
+     * @return submission_viewed
+     */
+    public static function create_from_submission(\assign $assign, \stdClass $submission) {
+        $data = array(
+            'objectid' => $submission->id,
+            'relateduserid' => $submission->userid,
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id,
+            ),
+        );
+        /** @var submission_viewed $event */
+        $event = self::create($data);
+        $event->set_assign($assign);
+        $event->add_record_snapshot('assign_submission', $submission);
+        return $event;
+    }
+
+    /**
+     * Init method.
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'assign_submission';
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
+    }
+
+    /**
+     * Returns localised general event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubmissionviewed', 'mod_assign');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with the id {$this->userid} viewed the submission for the user with the id {$this->relateduserid} for the
+            assignment with the id {$this->other['assignid']}.";
+    }
+
+    /**
+     * Return legacy data for add_to_log().
+     *
+     * @return array
+     */
+    protected function get_legacy_logdata() {
+        $logmessage = get_string('viewsubmissionforuser', 'assign', $this->relateduserid);
+        $this->set_legacy_logdata('view submission', $logmessage);
+        return parent::get_legacy_logdata();
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     */
+    protected function validate_data() {
+        parent::validate_data();
+
+        if (!isset($this->relateduserid)) {
+            throw new \coding_exception('The \'relateduserid\' must be set.');
+        }
+
+        if (!isset($this->other['assignid'])) {
+            throw new \coding_exception('The \'assignid\' must be set in other.');
+        }
+    }
+}
index d1cb048..3291942 100644 (file)
@@ -40,14 +40,40 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class workflow_state_updated extends \core\event\base {
+class workflow_state_updated extends base {
+    /**
+     * Flag for prevention of direct create() call.
+     * @var bool
+     */
+    protected static $preventcreatecall = true;
 
     /**
-     * Legacy log data.
+     * Create instance of event.
      *
-     * @var array
+     * @since Moodle 2.7
+     *
+     * @param \assign $assign
+     * @param \stdClass $user
+     * @param string $state
+     * @return workflow_state_updated
      */
-    protected $legacylogdata;
+    public static function create_from_user(\assign $assign, \stdClass $user, $state) {
+        $data = array(
+            'context' => $assign->get_context(),
+            'objectid' => $assign->get_instance()->id,
+            'relateduserid' => $user->id,
+            'other' => array(
+                'newstate' => $state,
+            ),
+        );
+        self::$preventcreatecall = false;
+        /** @var workflow_state_updated $event */
+        $event = self::create($data);
+        self::$preventcreatecall = true;
+        $event->set_assign($assign);
+        $event->add_record_snapshot('user', $user);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -58,31 +84,13 @@ class workflow_state_updated extends \core\event\base {
         return "User {$this->userid} has set the workflow state of {$this->relateduserid} to {$this->other['newstate']}.";
     }
 
-    /**
-     * Return legacy data for add_to_log().
-     *
-     * @return array
-     */
-    protected function get_legacy_logdata() {
-        return $this->legacylogdata;
-    }
-
     /**
      * Return localised event name.
      *
      * @return string
      */
     public static function get_name() {
-        return get_string('event_workflow_state_updated', 'mod_assign');
-    }
-
-    /**
-     * Get URL related to the action
-     *
-     * @return \moodle_url
-     */
-    public function get_url() {
-        return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid));
+        return get_string('eventworkflowstateupdated', 'mod_assign');
     }
 
     /**
@@ -97,23 +105,30 @@ class workflow_state_updated extends \core\event\base {
     }
 
     /**
-     * Sets the legacy event log data.
+     * Return legacy data for add_to_log().
      *
-     * @param \stdClass $legacylogdata legacy log data.
-     * @return void
+     * @return array
      */
-    public function set_legacy_logdata($legacylogdata) {
-        $this->legacylogdata = $legacylogdata;
+    protected function get_legacy_logdata() {
+        $user = $this->get_record_snapshot('user', $this->relateduserid);
+        $a = array('id' => $user->id, 'fullname' => fullname($user), 'state' => $this->other['newstate']);
+        $logmessage = get_string('setmarkingworkflowstateforlog', 'assign', $a);
+        $this->set_legacy_logdata('set marking workflow state', $logmessage);
+        return parent::get_legacy_logdata();
     }
 
     /**
      * Custom validation.
      *
      * @throws \coding_exception
-     * @return void
      */
     protected function validate_data() {
+        if (self::$preventcreatecall) {
+            throw new \coding_exception('cannot call workflow_state_updated::create() directly, use workflow_state_updated::create_from_user() instead.');
+        }
+
         parent::validate_data();
+
         if (!isset($this->other['newstate'])) {
             throw new \coding_exception('newstate must be set in $other.');
         } else if (!isset($this->relateduserid)) {
index fdfcc10..05b1dc5 100644 (file)
Binary files a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js and b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js differ
index 651bbd9..e03ddc0 100644 (file)
Binary files a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js and b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js differ
index fdfcc10..05b1dc5 100644 (file)
Binary files a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js and b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js differ
index 67f7af2..898179b 100644 (file)
@@ -205,7 +205,9 @@ EDITOR.prototype = {
 
             this.currentedit.start = false;
             this.currentedit.end = false;
-            this.quicklist = new M.assignfeedback_editpdf.quickcommentlist(this);
+            if (!this.get('readonly')) {
+                this.quicklist = new M.assignfeedback_editpdf.quickcommentlist(this);
+            }
         }
     },
 
@@ -462,7 +464,9 @@ EDITOR.prototype = {
         }
 
         // Update the ui.
-        this.quicklist.load();
+        if (this.quicklist) {
+            this.quicklist.load();
+        }
         this.setup_navigation();
         this.setup_toolbar();
         this.change_page();
index c47d036..8845e3c 100644 (file)
@@ -166,7 +166,6 @@ class assign_feedback_offline extends assign_feedback_plugin {
                 $grade->grader = $USER->id;
                 if ($this->assignment->update_grade($grade)) {
                     $this->assignment->notify_grade_modified($grade);
-                    $this->assignment->add_to_log('grade submission', $this->assignment->format_grade_for_log($grade));
                     $updatecount += 1;
                 }
             }
@@ -189,12 +188,15 @@ class assign_feedback_offline extends assign_feedback_plugin {
                         $grade = $this->assignment->get_user_grade($record->user->id, true);
                         $this->assignment->notify_grade_modified($grade);
                         if ($plugin->set_editor_text($field, $newvalue, $grade->id)) {
-                            $logdesc = get_string('feedbackupdate', 'assignfeedback_offline',
+                            $logdesc = new lang_string('feedbackupdate', 'assignfeedback_offline',
                                                   array('field'=>$description,
                                                         'student'=>$userdesc,
                                                         'text'=>$newvalue));
 
-                            $this->assignment->add_to_log('save grading feedback', $logdesc);
+                            // Trigger event for updating the feedback.
+                            $event = \mod_assign\event\feedback_updated::create_from_grade($this->assignment, $grade);
+                            $event->set_legacy_logdata('save grading feedback', $logdesc);
+                            $event->trigger();
                         }
 
                         // If this is the gradebook comments plugin - post an update to the gradebook.
index bc6d798..1151ddf 100644 (file)
@@ -32,7 +32,7 @@ require_login($course);
 $PAGE->set_url('/mod/assign/index.php', array('id' => $id));
 $PAGE->set_pagelayout('incourse');
 
-add_to_log($course->id, 'assign', 'view all', 'index.php?id=$course->id', '');
+\mod_assign\event\course_module_instance_list_viewed::create_from_course($course)->trigger();
 
 // Print the header.
 $strplural = get_string("modulenameplural", "assign");
index c5bde1d..83c66a3 100644 (file)
@@ -140,20 +140,31 @@ $string['editsubmissionother'] = 'Edit submission for {$a}';
 $string['editsubmission_help'] = 'Make changes to your submission';
 $string['editingstatus'] = 'Editing status';
 $string['editaction'] = 'Actions...';
-$string['event_assessable_submitted'] = 'A submission has been submitted.';
-$string['event_all_submissions_downloaded'] = 'All the submissions are being downloaded.';
-$string['event_extension_granted'] = 'An extension has been granted.';
-$string['event_identities_revealed'] = 'The identities have been revealed.';
-$string['event_marker_updated'] = 'The allocated marker has been updated.';
-$string['event_statement_accepted'] = 'The user has accepted the statement of the submission.';
-$string['event_submission_duplicated'] = 'The user duplicated his submission.';
-$string['event_submission_graded'] = 'The submission has been graded.';
-$string['event_submission_locked'] = 'The submissions have been locked for a user.';
-$string['event_submission_status_updated'] = 'The status of the submission has been updated.';
-$string['event_submission_unlocked'] = 'The submissions have been unlocked for a user.';
-$string['event_workflow_state_updated'] = 'The state of the workflow has been updated.';
+$string['eventallsubmissionsdownloaded'] = 'All the submissions are being downloaded.';
+$string['eventassessablesubmitted'] = 'A submission has been submitted.';
+$string['eventbatchsetmarkerallocationviewed'] = 'Batch set marker allocation viewed';
+$string['eventbatchsetworkflowstateviewed'] = 'Batch set workflow state viewed.';
+$string['eventextensiongranted'] = 'An extension has been granted.';
+$string['eventfeedbackupdated'] = 'Feedback updated';
+$string['eventfeedbackviewed'] = 'Feedback viewed';
+$string['eventgradingformviewed'] = 'Grading form viewed';
+$string['eventgradingtableviewed'] = 'Grading table viewed';
+$string['eventidentitiesrevealed'] = 'The identities have been revealed.';
+$string['eventmarkerupdated'] = 'The allocated marker has been updated.';
+$string['eventrevealidentitiesconfirmationpageviewed'] = 'Reveal identities confirmation page viewed.';
+$string['eventstatementaccepted'] = 'The user has accepted the statement of the submission.';
+$string['eventsubmissionconfirmationformviewed'] = 'Submission confirmation form viewed.';
 $string['eventsubmissioncreated'] = 'Submission created.';
+$string['eventsubmissionduplicated'] = 'The user duplicated his submission.';
+$string['eventsubmissionformviewed'] = 'Submission form viewed.';
+$string['eventsubmissiongraded'] = 'The submission has been graded.';
+$string['eventsubmissionlocked'] = 'The submissions have been locked for a user.';
+$string['eventsubmissionstatusupdated'] = 'The status of the submission has been updated.';
+$string['eventsubmissionstatusviewed'] = 'The status of the submission has been viewed.';
+$string['eventsubmissionunlocked'] = 'The submissions have been unlocked for a user.';
 $string['eventsubmissionupdated'] = 'Submission updated.';
+$string['eventsubmissionviewed'] = 'Submission viewed.';
+$string['eventworkflowstateupdated'] = 'The state of the workflow has been updated.';
 $string['extensionduedate'] = 'Extension due date';
 $string['extensionnotafterduedate'] = 'Extension date must be after the due date';
 $string['extensionnotafterfromdate'] = 'Extension date must be after the allow submissions from date';
index 04e5944..75239c0 100644 (file)
@@ -1837,6 +1837,7 @@ class assign {
 
         if ($result) {
             $this->gradebook_item_update(null, $grade);
+            \mod_assign\event\submission_graded::create_from_grade($this, $grade)->trigger();
         }
         return $result;
     }
@@ -2011,8 +2012,7 @@ class assign {
 
             $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
             $sid = $DB->insert_record('assign_submission', $submission);
-            $submission->id = $sid;
-            return $submission;
+            return $DB->get_record('assign_submission', array('id' => $sid));
         }
         return false;
     }
@@ -2150,8 +2150,6 @@ class assign {
      * @return string
      */
     protected function view_plugin_content($pluginsubtype) {
-        global $USER;
-
         $o = '';
 
         $submissionid = optional_param('sid', 0, PARAM_INT);
@@ -2179,8 +2177,9 @@ class assign {
                                                               $this->get_return_action(),
                                                               $this->get_return_params()));
 
-            $logmessage = get_string('viewsubmissionforuser', 'assign', $item->userid);
-            $this->add_to_log('view submission', $logmessage);
+            // Trigger event for viewing a submission.
+            \mod_assign\event\submission_viewed::create_from_submission($this, $item)->trigger();
+
         } else {
             $plugin = $this->get_feedback_plugin_by_type($plugintype);
             if ($gradeid <= 0) {
@@ -2200,13 +2199,15 @@ class assign {
                                                               $this->get_course_module()->id,
                                                               $this->get_return_action(),
                                                               $this->get_return_params()));
-            $logmessage = get_string('viewfeedbackforuser', 'assign', $item->userid);
-            $this->add_to_log('view feedback', $logmessage);
+
+            // Trigger event for viewing feedback.
+            \mod_assign\event\feedback_viewed::create_from_grade($this, $item)->trigger();
         }
 
         $o .= $this->view_return_links();
 
         $o .= $this->view_footer();
+
         return $o;
     }
 
@@ -2347,7 +2348,12 @@ class assign {
      * @return string
      */
     protected function view_footer() {
-        return $this->get_renderer()->render_footer();
+        // When viewing the footer during PHPUNIT tests a set_state error is thrown.
+        if (!PHPUNIT_TEST) {
+            return $this->get_renderer()->render_footer();
+        }
+
+        return '';
     }
 
     /**
@@ -2500,14 +2506,7 @@ class assign {
             $result .= $this->get_renderer()->continue_button($url);
             $result .= $this->view_footer();
         } else if ($zipfile = $this->pack_files($filesforzipping)) {
-            $addtolog = $this->add_to_log('download all submissions', get_string('downloadall', 'assign'), '', true);
-            $params = array(
-                'context' => $this->context,
-                'objectid' => $this->get_instance()->id
-            );
-            $event = \mod_assign\event\all_submissions_downloaded::create($params);
-            $event->set_legacy_logdata($addtolog);
-            $event->trigger();
+            \mod_assign\event\all_submissions_downloaded::create_from_assign($this)->trigger();
             // Send file and delete after sending.
             send_temp_file($zipfile, $filename);
             // We will not get here - send_temp_file calls exit.
@@ -2518,6 +2517,9 @@ class assign {
     /**
      * Util function to add a message to the log.
      *
+     * @deprecated since 2.7 - Use new events system instead.
+     *             (see http://docs.moodle.org/dev/Migrating_logging_calls_in_plugins).
+     *
      * @param string $action The current action
      * @param string $info A detailed description of the change. But no more than 255 characters.
      * @param string $url The url to the assign module instance.
@@ -2543,6 +2545,9 @@ class assign {
         );
 
         if ($return) {
+            // We only need to call debugging when returning a value. This is because the call to
+            // call_user_func_array('add_to_log', $args) will trigger a debugging message of it's own.
+            debugging('The mod_assign add_to_log() function is now deprecated.', DEBUG_DEVELOPER);
             return $args;
         }
         call_user_func_array('add_to_log', $args);
@@ -2610,8 +2615,7 @@ class assign {
                 $submission->attemptnumber = 0;
             }
             $sid = $DB->insert_record('assign_submission', $submission);
-            $submission->id = $sid;
-            return $submission;
+            return $DB->get_record('assign_submission', array('id' => $sid));
         }
         return false;
     }
@@ -2919,10 +2923,7 @@ class assign {
             $o .= $this->get_renderer()->render($history);
         }
 
-        $msg = get_string('viewgradingformforstudent',
-                          'assign',
-                          array('id'=>$user->id, 'fullname'=>fullname($user)));
-        $this->add_to_log('view grading form', $msg);
+        \mod_assign\event\grading_form_viewed::create_from_user($this, $user)->trigger();
 
         $o .= $this->view_footer();
         return $o;
@@ -2934,8 +2935,6 @@ class assign {
      * @return string
      */
     protected function view_reveal_identities_confirm() {
-        global $CFG, $USER;
-
         require_capability('mod/assign:revealidentities', $this->get_context());
 
         $o = '';
@@ -2958,7 +2957,9 @@ class assign {
                                              $confirmurl,
                                              $cancelurl);
         $o .= $this->view_footer();
-        $this->add_to_log('view', get_string('viewrevealidentitiesconfirm', 'assign'));
+
+        \mod_assign\event\reveal_identities_confirmation_page_viewed::create_from_assign($this)->trigger();
+
         return $o;
     }
 
@@ -3176,15 +3177,15 @@ class assign {
 
         $o .= $this->view_footer();
 
-        $logmessage = get_string('viewsubmissiongradingtable', 'assign');
-        $this->add_to_log('view submission grading table', $logmessage);
+        \mod_assign\event\grading_table_viewed::create_from_assign($this)->trigger();
+
         return $o;
     }
 
     /**
      * Capture the output of the plagiarism plugins disclosures and return it as a string.
      *
-     * @return void
+     * @return string
      */
     protected function plagiarism_print_disclosure() {
         global $CFG;
@@ -3260,7 +3261,7 @@ class assign {
         require_once($CFG->dirroot . '/mod/assign/submission_form.php');
         // Need submit permission to submit an assignment.
         $userid = optional_param('userid', $USER->id, PARAM_INT);
-        $user = clone($USER);
+        $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
         if ($userid == $USER->id) {
             // User is editing their own submission.
             require_capability('mod/assign:submit', $this->context);
@@ -3271,7 +3272,6 @@ class assign {
                 print_error('nopermission');
             }
 
-            $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
             $name = $this->fullname($user);
             $title = get_string('editsubmissionother', 'assign', $name);
         }
@@ -3303,7 +3303,8 @@ class assign {
         $o .= $this->get_renderer()->render(new assign_form('editsubmissionform', $mform));
 
         $o .= $this->view_footer();
-        $this->add_to_log('view submit assignment form', $title);
+
+        \mod_assign\event\submission_form_viewed::create_from_user($this, $user)->trigger();
 
         return $o;
     }
@@ -3477,7 +3478,7 @@ class assign {
      * @param moodleform $mform Set to a grading batch operations form
      * @return string - the page to view after processing these actions
      */
-    private function view_batch_set_workflow_state($mform) {
+    protected function view_batch_set_workflow_state($mform) {
         global $CFG, $DB;
 
         require_once($CFG->dirroot . '/mod/assign/batchsetmarkingworkflowstateform.php');
@@ -3522,7 +3523,8 @@ class assign {
         $o .= $this->get_renderer()->render(new assign_form('setworkflowstate', $mform));
         $o .= $this->view_footer();
 
-        $this->add_to_log('view batch set marking workflow state', get_string('viewbatchsetmarkingworkflowstate', 'assign'));
+        \mod_assign\event\batch_set_workflow_state_viewed::create_from_assign($this)->trigger();
+
         return $o;
     }
 
@@ -3532,7 +3534,7 @@ class assign {
      * @param moodleform $mform Set to a grading batch operations form
      * @return string - the page to view after processing these actions
      */
-    private function view_batch_markingallocation($mform) {
+    public function view_batch_markingallocation($mform) {
         global $CFG, $DB;
 
         require_once($CFG->dirroot . '/mod/assign/batchsetallocatedmarkerform.php');
@@ -3583,7 +3585,8 @@ class assign {
         $o .= $this->get_renderer()->render(new assign_form('setworkflowstate', $mform));
         $o .= $this->view_footer();
 
-        $this->add_to_log('view batch set marker allocation', get_string('viewbatchmarkingallocation', 'assign'));
+        \mod_assign\event\batch_set_marker_allocation_viewed::create_from_assign($this)->trigger();
+
         return $o;
     }
 
@@ -3635,8 +3638,7 @@ class assign {
         $o .= $this->get_renderer()->render($submitforgradingpage);
         $o .= $this->view_footer();
 
-        $logmessage = get_string('viewownsubmissionform', 'assign');
-        $this->add_to_log('view confirm submit assignment form', $logmessage);
+        \mod_assign\event\submission_confirmation_form_viewed::create_from_assign($this)->trigger();
 
         return $o;
     }
@@ -4022,7 +4024,9 @@ class assign {
         }
 
         $o .= $this->view_footer();
-        $this->add_to_log('view', get_string('viewownsubmissionstatus', 'assign'));
+
+        \mod_assign\event\submission_status_viewed::create_from_assign($this)->trigger();
+
         return $o;
     }
 
@@ -4755,26 +4759,13 @@ class assign {
             }
 
             if (!empty($data->submissionstatement) && $USER->id == $userid) {
-                $logmessage = get_string('submissionstatementacceptedlog',
-                                         'mod_assign',
-                                         fullname($USER));
-                $this->add_to_log('submission statement accepted', $logmessage);
+                \mod_assign\event\statement_accepted::create_from_submission($this, $submission)->trigger();
             }
-            $logdata = $this->add_to_log('submit for grading', $this->format_submission_for_log($submission), '', true);
             $this->notify_graders($submission);
             $this->notify_student_submission_receipt($submission);
 
-            // Trigger assessable_submitted event on submission.
-            $params = array(
-                'context' => context_module::instance($this->get_course_module()->id),
-                'objectid' => $submission->id,
-                'other' => array(
-                    'submission_editable' => false
-                )
-            );
-            $event = \mod_assign\event\assessable_submitted::create($params);
-            $event->set_legacy_logdata($logdata);
-            $event->trigger();
+            \mod_assign\event\assessable_submitted::create_from_submission($this, $submission, false)->trigger();
+
             return true;
         }
         $notices[] = get_string('submissionsclosed', 'assign');
@@ -4884,15 +4875,7 @@ class assign {
         $result = $this->update_user_flags($flags);
 
         if ($result) {
-            $addtolog = $this->add_to_log('grant extension', $userid, '', true);
-            $params = array(
-                'context' => $this->context,
-                'objectid' => $flags->assignment,
-                'relateduserid' => $userid
-            );
-            $event = \mod_assign\event\extension_granted::create($params);
-            $event->set_legacy_logdata($addtolog);
-            $event->trigger();
+            \mod_assign\event\extension_granted::create_from_assign($this, $userid)->trigger();
         }
         return $result;
     }
@@ -5147,16 +5130,6 @@ class assign {
                                           $data);
                 }
             }
-
-            $addtolog = $this->add_to_log('grade submission', $this->format_grade_for_log($grade), '', true);
-            $params = array(
-                'context' => $this->context,
-                'objectid' => $grade->id,
-                'relateduserid' => $userid
-            );
-            $event = \mod_assign\event\submission_graded::create($params);
-            $event->set_legacy_logdata($addtolog);
-            $event->trigger();
         }
 
         return get_string('quickgradingchangessaved', 'assign');
@@ -5206,14 +5179,7 @@ class assign {
             $this->gradebook_item_update(null, $grade);
         }
 
-        $addtolog = $this->add_to_log('reveal identities', get_string('revealidentities', 'assign'), '', true);
-        $params = array(
-            'context' => $this->context,
-            'objectid' => $update->id
-        );
-        $event = \mod_assign\event\identities_revealed::create($params);
-        $event->set_legacy_logdata($addtolog);
-        $event->trigger();
+        \mod_assign\event\identities_revealed::create_from_assign($this)->trigger();
     }
 
     /**
@@ -5316,6 +5282,8 @@ class assign {
      * The size limit for the log file is 255 characters, so be careful not
      * to include too much information.
      *
+     * @deprecated since 2.7
+     *
      * @param stdClass $grade
      * @return string
      */
@@ -5338,10 +5306,12 @@ class assign {
      * The size limit for the log file is 255 characters, so be careful not
      * to include too much information.
      *
+     * @deprecated since 2.7
+     *
      * @param stdClass $submission
      * @return string
      */
-    protected function format_submission_for_log(stdClass $submission) {
+    public function format_submission_for_log(stdClass $submission) {
         global $DB;
 
         $info = '';
@@ -5439,14 +5409,7 @@ class assign {
             return false;
         }
 
-        $addtolog = $this->add_to_log('submissioncopied', $this->format_submission_for_log($submission), '', true);
-        $params = array(
-            'context' => $this->context,
-            'objectid' => $submission->id
-        );
-        $event = \mod_assign\event\submission_duplicated::create($params);
-        $event->set_legacy_logdata($addtolog);
-        $event->trigger();
+        \mod_assign\event\submission_duplicated::create_from_submission($this, $submission)->trigger();
 
         $complete = COMPLETION_INCOMPLETE;
         if ($submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
@@ -5463,19 +5426,11 @@ class assign {
             // is clear that the submission was copied.
             $this->notify_student_submission_copied($submission);
             $this->notify_graders($submission);
-            // Trigger assessable_submitted event on submission.
+
             // The same logic applies here - we could not notify teachers,
             // but then they would wonder why there are submitted assignments
             // and they haven't been notified.
-            $params = array(
-                'context' => context_module::instance($this->get_course_module()->id),
-                'objectid' => $submission->id,
-                'other' => array(
-                    'submission_editable' => true
-                )
-            );
-            $event = \mod_assign\event\assessable_submitted::create($params);
-            $event->trigger();
+            \mod_assign\event\assessable_submitted::create_from_submission($this, $submission, true)->trigger();
         }
         return true;
     }
@@ -5554,6 +5509,7 @@ class assign {
                 }
             }
         }
+
         $allempty = $this->submission_empty($submission);
         if ($pluginerror || $allempty) {
             if ($allempty) {
@@ -5566,18 +5522,7 @@ class assign {
 
         // Logging.
         if (isset($data->submissionstatement) && ($userid == $USER->id)) {
-            $logmessage = get_string('submissionstatementacceptedlog',
-                                     'mod_assign',
-                                     fullname($USER));
-            $this->add_to_log('submission statement accepted', $logmessage);
-            $addtolog = $this->add_to_log('submission statement accepted', $logmessage, '', true);
-            $params = array(
-                'context' => $this->context,
-                'objectid' => $submission->id
-            );
-            $event = \mod_assign\event\statement_accepted::create($params);
-            $event->set_legacy_logdata($addtolog);
-            $event->trigger();
+            \mod_assign\event\statement_accepted::create_from_submission($this, $submission)->trigger();
         }
 
         $complete = COMPLETION_INCOMPLETE;
@@ -5592,16 +5537,7 @@ class assign {
         if (!$instance->submissiondrafts) {
             $this->notify_student_submission_receipt($submission);
             $this->notify_graders($submission);
-            // Trigger assessable_submitted event on submission.
-            $params = array(
-                'context' => context_module::instance($this->get_course_module()->id),
-                'objectid' => $submission->id,
-                'other' => array(
-                    'submission_editable' => true
-                )
-            );
-            $event = \mod_assign\event\assessable_submitted::create($params);
-            $event->trigger();
+            \mod_assign\event\assessable_submitted::create_from_submission($this, $submission, true)->trigger();
         }
         return true;
     }
@@ -6111,28 +6047,12 @@ class assign {
         $grade->grader = $USER->id;
         $this->update_grade($grade);
 
-        $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
-
         $completion = new completion_info($this->get_course());
         if ($completion->is_enabled($this->get_course_module()) &&
                 $this->get_instance()->completionsubmit) {
             $completion->update_state($this->get_course_module(), COMPLETION_INCOMPLETE, $userid);
         }
-        $logmessage = get_string('reverttodraftforstudent',
-                                 'assign',
-                                 array('id'=>$user->id, 'fullname'=>fullname($user)));
-        $addtolog = $this->add_to_log('revert submission to draft', $logmessage, '', true);
-        $params = array(
-            'context' => $this->context,
-            'objectid' => $submission->id,
-            'relateduserid' => ($this->get_instance()->teamsubmission) ? null : $userid,
-            'other' => array(
-                'newstatus' => $submission->status
-            )
-        );
-        $event = \mod_assign\event\submission_status_updated::create($params);
-        $event->set_legacy_logdata($addtolog);
-        $event->trigger();
+        \mod_assign\event\submission_status_updated::create_from_submission($this, $submission)->trigger();
         return true;
     }
 
@@ -6179,19 +6099,7 @@ class assign {
         }
 
         $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
-
-        $logmessage = get_string('locksubmissionforstudent',
-                                 'assign',
-                                 array('id'=>$user->id, 'fullname'=>fullname($user)));
-        $addtolog = $this->add_to_log('lock submission', $logmessage, '', true);
-        $params = array(
-            'context' => $this->context,
-            'objectid' => $flags->assignment,
-            'relateduserid' => $user->id
-        );
-        $event = \mod_assign\event\submission_locked::create($params);
-        $event->set_legacy_logdata($addtolog);
-        $event->trigger();
+        \mod_assign\event\submission_locked::create_from_user($this, $user)->trigger();
         return true;
     }
 
@@ -6229,23 +6137,7 @@ class assign {
                 }
 
                 $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
-
-                $params = array('id'=>$user->id,
-                                'fullname'=>fullname($user),
-                                'state'=>$state);
-                $message = get_string('setmarkingworkflowstateforlog', 'assign', $params);
-                $addtolog = $this->add_to_log('set marking workflow state', $message, '', true);
-                $params = array(
-                    'context' => $this->context,
-                    'objectid' => $this->get_instance()->id,
-                    'relateduserid' => $userid,
-                    'other' => array(
-                        'newstate' => $state
-                    )
-                );
-                $event = \mod_assign\event\workflow_state_updated::create($params);
-                $event->set_legacy_logdata($addtolog);
-                $event->trigger();
+                \mod_assign\event\workflow_state_updated::create_from_user($this, $user, $state)->trigger();
             }
         }
     }
@@ -6280,25 +6172,8 @@ class assign {
             $flags->allocatedmarker = $marker->id;
 
             if ($this->update_user_flags($flags)) {
-
                 $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
-
-                $params = array('id'=>$user->id,
-                    'fullname'=>fullname($user),
-                    'marker'=>fullname($marker));
-                $message = get_string('setmarkerallocationforlog', 'assign', $params);
-                $addtolog = $this->add_to_log('set marking allocation', $message, '', true);
-                $params = array(
-                    'context' => $this->context,
-                    'objectid' => $this->get_instance()->id,
-                    'relateduserid' => $userid,
-                    'other' => array(
-                        'markerid' => $marker->id
-                    )
-                );
-                $event = \mod_assign\event\marker_updated::create($params);
-                $event->set_legacy_logdata($addtolog);
-                $event->trigger();
+                \mod_assign\event\marker_updated::create_from_marker($this, $user, $marker)->trigger();
             }
         }
     }
@@ -6349,19 +6224,7 @@ class assign {
         }
 
         $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
-
-        $logmessage = get_string('unlocksubmissionforstudent',
-                                 'assign',
-                                 array('id'=>$user->id, 'fullname'=>fullname($user)));
-        $addtolog = $this->add_to_log('unlock submission', $logmessage, '', true);
-        $params = array(
-            'context' => $this->context,
-            'objectid' => $flags->assignment,
-            'relateduserid' => $user->id
-        );
-        $event = \mod_assign\event\submission_unlocked::create($params);
-        $event->set_legacy_logdata($addtolog);
-        $event->trigger();
+        \mod_assign\event\submission_unlocked::create_from_user($this, $user)->trigger();
         return true;
     }
 
@@ -6439,16 +6302,6 @@ class assign {
         if (!isset($formdata->sendstudentnotifications) || $formdata->sendstudentnotifications) {
             $this->notify_grade_modified($grade);
         }
-
-        $addtolog = $this->add_to_log('grade submission', $this->format_grade_for_log($grade), '', true);
-        $params = array(
-            'context' => $this->context,
-            'objectid' => $grade->id,
-            'relateduserid' => $userid
-        );
-        $event = \mod_assign\event\submission_graded::create($params);
-        $event->set_legacy_logdata($addtolog);
-        $event->trigger();
     }
 
 
index eda470d..2c1b5c5 100644 (file)
@@ -227,6 +227,9 @@ class assign_submission_file extends assign_submission_plugin {
                 'pathnamehashes' => array_keys($files)
             )
         );
+        if (!empty($submission->userid) && ($submission->userid != $USER->id)) {
+            $params->relateduserid = $submission->userid;
+        }
         $event = \assignsubmission_file\event\assessable_uploaded::create($params);
         $event->set_legacy_files($files);
         $event->trigger();
@@ -260,6 +263,7 @@ class assign_submission_file extends assign_submission_plugin {
             $params['objectid'] = $filesubmission->id;
 
             $event = \assignsubmission_file\event\submission_updated::create($params);
+            $event->set_assign($this->assignment);
             $event->trigger();
             return $updatestatus;
         } else {
@@ -272,6 +276,7 @@ class assign_submission_file extends assign_submission_plugin {
             $params['objectid'] = $filesubmission->id;
 
             $event = \assignsubmission_file\event\submission_created::create($params);
+            $event->set_assign($this->assignment);
             $event->trigger();
             return $filesubmission->id > 0;
         }
index 790c0ec..627c6a1 100644 (file)
@@ -228,6 +228,9 @@ class assign_submission_onlinetext extends assign_submission_plugin {
                 'format' => $data->onlinetext_editor['format']
             )
         );
+        if (!empty($submission->userid) && ($submission->userid != $USER->id)) {
+            $params['relateduserid'] = $submission->userid;
+        }
         $event = \assignsubmission_onlinetext\event\assessable_uploaded::create($params);
         $event->trigger();
 
@@ -262,6 +265,7 @@ class assign_submission_onlinetext extends assign_submission_plugin {
             $params['objectid'] = $onlinetextsubmission->id;
             $updatestatus = $DB->update_record('assignsubmission_onlinetext', $onlinetextsubmission);
             $event = \assignsubmission_onlinetext\event\submission_updated::create($params);
+            $event->set_assign($this->assignment);
             $event->trigger();
             return $updatestatus;
         } else {
@@ -275,6 +279,7 @@ class assign_submission_onlinetext extends assign_submission_plugin {
             $onlinetextsubmission->id = $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission);
             $params['objectid'] = $onlinetextsubmission->id;
             $event = \assignsubmission_onlinetext\event\submission_created::create($params);
+            $event->set_assign($this->assignment);
             $event->trigger();
             return $onlinetextsubmission->id > 0;
         }
index 9155540..84adc01 100644 (file)
@@ -290,4 +290,48 @@ class testable_assign extends assign {
         // Changed method from protected to public.
         return parent::get_graders($userid);
     }
+
+    public function testable_view_batch_set_workflow_state() {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/mod/assign/batchsetmarkingworkflowstateform.php');
+
+        // Mock submit data.
+        $data = array();
+        $data['selectedusers'] = '1';
+        mod_assign_batch_set_marking_workflow_state_form::mock_submit($data);
+
+        // Set required variables in the form - not valid just allows us to continue.
+        $formparams = array();
+        $formparams['users'] = array(1);
+        $formparams['usershtml'] = 1;
+        $formparams['cm'] = $this->get_course_module()->id;
+        $formparams['context'] = $this->get_context();
+        $formparams['markingworkflowstates'] = 1;
+        $mform = new mod_assign_batch_set_marking_workflow_state_form('', $formparams);
+
+        return parent::view_batch_set_workflow_state($mform);
+    }
+
+    public function testable_view_batch_markingallocation() {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/mod/assign/batchsetallocatedmarkerform.php');
+
+        // Mock submit data.
+        $data = array();
+        $data['selectedusers'] = '1';
+        mod_assign_batch_set_allocatedmarker_form::mock_submit($data);
+
+        // Set required variables in the form - not valid just allows us to continue.
+        $formparams = array();
+        $formparams['users'] = array(1);
+        $formparams['usershtml'] = 1;
+        $formparams['cm'] = $this->get_course_module()->id;
+        $formparams['context'] = $this->get_context();
+        $formparams['markers'] = 1;
+        $mform = new mod_assign_batch_set_allocatedmarker_form('', $formparams);
+
+        return parent::view_batch_markingallocation($mform);
+    }
 }
diff --git a/mod/assign/tests/event_test.php b/mod/assign/tests/event_test.php
deleted file mode 100644 (file)
index 1175360..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-<?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/>.
-
-/**
- * Contains the event tests for the module assign.
- *
- * @package   mod_assign
- * @copyright 2014 Adrian Greeve <adrian@moodle.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
-require_once($CFG->dirroot . '/mod/assign/tests/fixtures/event_mod_assign_fixtures.php');
-
-/**
- * Contains the event tests for the module assign.
- *
- * @package   mod_assign
- * @copyright 2014 Adrian Greeve <adrian@moodle.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class assign_events_testcase extends advanced_testcase {
-
-    /** @var stdClass $user A user to submit an assignment. */
-    protected $user;
-
-    /** @var stdClass $course New course created to hold the assignment activity. */
-    protected $course;
-
-    /** @var stdClass $cm A context module object. */
-    protected $cm;
-
-    /** @var stdClass $context Context of the assignment activity. */
-    protected $context;
-
-    /** @var array $params Standard event parameters. */
-    protected $params;
-
-    /**
-     * Setup all the various parts of an assignment activity.
-     */
-    protected function setUp() {
-        $this->user = $this->getDataGenerator()->create_user();
-        $this->course = $this->getDataGenerator()->create_course();
-        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
-        $instance = $generator->create_instance(array('course' => $this->course->id));
-        $this->cm = get_coursemodule_from_instance('assign', $instance->id);
-        $this->context = context_module::instance($this->cm->id);
-
-        // Standard Event parameters.
-        $this->params = array(
-            'context' => $this->context,
-            'courseid' => $this->course->id
-        );
-    }
-
-    /**
-     * Basic tests for the submission_created() abstract class.
-     */
-    public function test_submission_created() {
-        $this->resetAfterTest();
-
-        $eventinfo = $this->params;
-        $eventinfo['other'] = array(
-            'submissionid' => '17',
-            'submissionattempt' => 0,
-            'submissionstatus' => 'submitted'
-        );
-
-        $sink = $this->redirectEvents();
-        $event = \mod_assign_unittests\event\submission_created::create($eventinfo);
-        $event->trigger();
-        $result = $sink->get_events();
-        $event = reset($result);
-        $sink->close();
-
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
-
-        // Check that an error occurs when teamsubmission is not set.
-        try {
-            \mod_assign_unittests\event\submission_created::create($this->params);
-            $this->fail('Other must contain the key submissionid.');
-        } catch (Exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
-        // Check that the submission status debugging is fired.
-        $subinfo = $this->params;
-        $subinfo['other'] = array('submissionid' => '23');
-        try {
-            \mod_assign_unittests\event\submission_created::create($subinfo);
-            $this->fail('Other must contain the key submissionattempt.');
-        } catch (Exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
-
-        $subinfo['other'] = array('submissionattempt' => '0');
-        try {
-            \mod_assign_unittests\event\submission_created::create($subinfo);
-            $this->fail('Other must contain the key submissionstatus.');
-        } catch (Exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
-    }
-
-    /**
-     * Basic tests for the submission_updated() abstract class.
-     */
-    public function test_submission_updated() {
-        $this->resetAfterTest();
-
-        $eventinfo = $this->params;
-        $eventinfo['other'] = array(
-            'submissionid' => '17',
-            'submissionattempt' => 0,
-            'submissionstatus' => 'submitted'
-        );
-
-        $sink = $this->redirectEvents();
-        $event = \mod_assign_unittests\event\submission_updated::create($eventinfo);
-        $event->trigger();
-        $result = $sink->get_events();
-        $event = reset($result);
-        $sink->close();
-
-        $this->assertEquals($this->context->id, $event->contextid);
-        $this->assertEquals($this->course->id, $event->courseid);
-
-        // Check that an error occurs when teamsubmission is not set.
-        try {
-            \mod_assign_unittests\event\submission_created::create($this->params);
-            $this->fail('Other must contain the key submissionid.');
-        } catch (Exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
-        // Check that the submission status debugging is fired.
-        $subinfo = $this->params;
-        $subinfo['other'] = array('submissionid' => '23');
-        try {
-            \mod_assign_unittests\event\submission_created::create($subinfo);
-            $this->fail('Other must contain the key submissionattempt.');
-        } catch (Exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
-
-        $subinfo['other'] = array('submissionattempt' => '0');
-        try {
-            \mod_assign_unittests\event\submission_created::create($subinfo);
-            $this->fail('Other must contain the key submissionstatus.');
-        } catch (Exception $e) {
-            $this->assertInstanceOf('coding_exception', $e);
-        }
-    }
-}
-
diff --git a/mod/assign/tests/events_test.php b/mod/assign/tests/events_test.php
new file mode 100644 (file)
index 0000000..ac391b9
--- /dev/null
@@ -0,0 +1,994 @@
+<?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/>.
+
+/**
+ * Contains the event tests for the module assign.
+ *
+ * @package   mod_assign
+ * @copyright 2014 Adrian Greeve <adrian@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
+require_once($CFG->dirroot . '/mod/assign/tests/fixtures/event_mod_assign_fixtures.php');
+
+/**
+ * Contains the event tests for the module assign.
+ *
+ * @package   mod_assign
+ * @copyright 2014 Adrian Greeve <adrian@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class assign_events_testcase extends mod_assign_base_testcase {
+
+    /**
+     * Basic tests for the submission_created() abstract class.
+     */
+    public function test_base_event() {
+        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $instance = $generator->create_instance(array('course' => $this->course->id));
+        $modcontext = context_module::instance($instance->cmid);
+
+        $data = array(
+            'context' => $modcontext,
+        );
+        /** @var \mod_assign_unittests\event\nothing_happened $event */
+        $event = \mod_assign_unittests\event\nothing_happened::create($data);
+        $assign = $event->get_assign();
+        $this->assertDebuggingCalled();
+        $this->assertInstanceOf('assign', $assign);
+
+        $event = \mod_assign_unittests\event\nothing_happened::create($data);
+        $event->set_assign($assign);
+        $assign2 = $event->get_assign();
+        $this->assertDebuggingNotCalled();
+        $this->assertSame($assign, $assign2);
+    }
+
+    /**
+     * Basic tests for the submission_created() abstract class.
+     */
+    public function test_submission_created() {
+        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $instance = $generator->create_instance(array('course' => $this->course->id));
+        $modcontext = context_module::instance($instance->cmid);
+
+        // Standard Event parameters.
+        $params = array(
+            'context' => $modcontext,
+            'courseid' => $this->course->id
+        );
+
+        $eventinfo = $params;
+        $eventinfo['other'] = array(
+            'submissionid' => '17',
+            'submissionattempt' => 0,
+            'submissionstatus' => 'submitted'
+        );
+
+        $sink = $this->redirectEvents();
+        $event = \mod_assign_unittests\event\submission_created::create($eventinfo);
+        $event->trigger();
+        $result = $sink->get_events();
+        $event = reset($result);
+        $sink->close();
+
+        $this->assertEquals($modcontext->id, $event->contextid);
+        $this->assertEquals($this->course->id, $event->courseid);
+
+        // Check that an error occurs when teamsubmission is not set.
+        try {
+            \mod_assign_unittests\event\submission_created::create($params);
+            $this->fail('Other must contain the key submissionid.');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+        // Check that the submission status debugging is fired.
+        $subinfo = $params;
+        $subinfo['other'] = array('submissionid' => '23');
+        try {
+            \mod_assign_unittests\event\submission_created::create($subinfo);
+            $this->fail('Other must contain the key submissionattempt.');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+
+        $subinfo['other'] = array('submissionattempt' => '0');
+        try {
+            \mod_assign_unittests\event\submission_created::create($subinfo);
+            $this->fail('Other must contain the key submissionstatus.');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+    }
+
+    /**
+     * Basic tests for the submission_updated() abstract class.
+     */
+    public function test_submission_updated() {
+        $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $instance = $generator->create_instance(array('course' => $this->course->id));
+        $modcontext = context_module::instance($instance->cmid);
+
+        // Standard Event parameters.
+        $params = array(
+            'context' => $modcontext,
+            'courseid' => $this->course->id
+        );
+
+        $eventinfo = $params;
+        $eventinfo['other'] = array(
+            'submissionid' => '17',
+            'submissionattempt' => 0,
+            'submissionstatus' => 'submitted'
+        );
+
+        $sink = $this->redirectEvents();
+        $event = \mod_assign_unittests\event\submission_updated::create($eventinfo);
+        $event->trigger();
+        $result = $sink->get_events();
+        $event = reset($result);
+        $sink->close();
+
+        $this->assertEquals($modcontext->id, $event->contextid);
+        $this->assertEquals($this->course->id, $event->courseid);
+
+        // Check that an error occurs when teamsubmission is not set.
+        try {
+            \mod_assign_unittests\event\submission_created::create($params);
+            $this->fail('Other must contain the key submissionid.');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+        // Check that the submission status debugging is fired.
+        $subinfo = $params;
+        $subinfo['other'] = array('submissionid' => '23');
+        try {
+            \mod_assign_unittests\event\submission_created::create($subinfo);
+            $this->fail('Other must contain the key submissionattempt.');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+
+        $subinfo['other'] = array('submissionattempt' => '0');
+        try {
+            \mod_assign_unittests\event\submission_created::create($subinfo);
+            $this->fail('Other must contain the key submissionstatus.');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+    }
+
+    public function test_extension_granted() {
+        $this->setUser($this->editingteachers[0]);
+
+        $tomorrow = time() + 24*60*60;
+        $yesterday = time() - 24*60*60;
+
+        $assign = $this->create_instance(array('duedate' => $yesterday, 'cutoffdate' => $yesterday));
+        $sink = $this->redirectEvents();
+
+        $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\extension_granted', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($assign->get_instance()->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'grant extension',
+            'view.php?id=' . $assign->get_course_module()->id,
+            $this->students[0]->id,
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+    }
+
+    public function test_submission_locked() {
+        $this->editingteachers[0]->ignoresesskey = true;
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+        $sink = $this->redirectEvents();
+
+        $assign->lock_submission($this->students[0]->id);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\submission_locked', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($assign->get_instance()->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'lock submission',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('locksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
+                'fullname' => fullname($this->students[0]))),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Revert to defaults.
+        $this->editingteachers[0]->ignoresesskey = false;
+    }
+
+    public function test_identities_revealed() {
+        $this->editingteachers[0]->ignoresesskey = true;
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance(array('blindmarking'=>1));
+        $sink = $this->redirectEvents();
+
+        $assign->reveal_identities();
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\identities_revealed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($assign->get_instance()->id, $event->objectid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'reveal identities',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('revealidentities', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Revert to defaults.
+        $this->editingteachers[0]->ignoresesskey = false;
+    }
+
+    /**
+     * Test the submission_status_viewed event.
+     */
+    public function test_submission_status_viewed() {
+        global $PAGE;
+
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+
+        // We need to set the URL in order to view the feedback.
+        $PAGE->set_url('/a_url');
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view();
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\submission_status_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewownsubmissionstatus', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    public function test_submission_status_updated() {
+        $this->editingteachers[0]->ignoresesskey = true;
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
+
+        $sink = $this->redirectEvents();
+        $assign->revert_to_draft($this->students[0]->id);
+
+        $events = $sink->get_events();
+        $this->assertCount(2, $events);
+        $event = $events[1];
+        $this->assertInstanceOf('\mod_assign\event\submission_status_updated', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($submission->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals(ASSIGN_SUBMISSION_STATUS_DRAFT, $event->other['newstatus']);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'revert submission to draft',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('reverttodraftforstudent', 'assign', array('id' => $this->students[0]->id,
+                'fullname' => fullname($this->students[0]))),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Revert to defaults.
+        $this->editingteachers[0]->ignoresesskey = false;
+    }
+
+    public function test_marker_updated() {
+        $this->editingteachers[0]->ignoresesskey = true;
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+
+        $sink = $this->redirectEvents();
+        $assign->testable_process_set_batch_marking_allocation($this->students[0]->id, $this->teachers[0]->id);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\marker_updated', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($assign->get_instance()->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
+        $this->assertEquals($this->teachers[0]->id, $event->other['markerid']);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'set marking allocation',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('setmarkerallocationforlog', 'assign', array('id' => $this->students[0]->id,
+                'fullname' => fullname($this->students[0]), 'marker' => fullname($this->teachers[0]))),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Revert to defaults.
+        $this->editingteachers[0]->ignoresesskey = false;
+    }
+
+    public function test_workflow_state_updated() {
+        $this->editingteachers[0]->ignoresesskey = true;
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+
+        $sink = $this->redirectEvents();
+        $assign->testable_process_set_batch_marking_workflow_state($this->students[0]->id, ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($assign->get_instance()->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
+        $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW, $event->other['newstate']);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'set marking workflow state',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
+                'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW)),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Revert to defaults.
+        $this->editingteachers[0]->ignoresesskey = false;
+    }
+
+    public function test_submission_duplicated() {
+        $this->setUser($this->students[0]);
+
+        $assign = $this->create_instance();
+        $submission1 = $assign->get_user_submission($this->students[0]->id, true, 0);
+        $submission2 = $assign->get_user_submission($this->students[0]->id, true, 1);
+        $submission2->status = ASSIGN_SUBMISSION_STATUS_REOPENED;
+        $assign->testable_update_submission($submission2, $this->students[0]->id, time(), $assign->get_instance()->teamsubmission);
+
+        $sink = $this->redirectEvents();
+        $notices = null;
+        $assign->copy_previous_attempt($notices);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\submission_duplicated', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($submission2->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->userid);
+        $submission2->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'submissioncopied',
+            'view.php?id=' . $assign->get_course_module()->id,
+            $assign->testable_format_submission_for_log($submission2),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+    }
+
+    public function test_submission_unlocked() {
+        $this->editingteachers[0]->ignoresesskey = true;
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+        $sink = $this->redirectEvents();
+
+        $assign->unlock_submission($this->students[0]->id);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\submission_unlocked', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($assign->get_instance()->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'unlock submission',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('unlocksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
+                'fullname' => fullname($this->students[0]))),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Revert to defaults.
+        $this->editingteachers[0]->ignoresesskey = false;
+    }
+
+    public function test_submission_graded() {
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance();
+
+        // Test apply_grade_to_user.
+        $sink = $this->redirectEvents();
+
+        $data = new stdClass();
+        $data->grade = '50.0';
+        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($grade->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'grade submission',
+            'view.php?id=' . $assign->get_course_module()->id,
+            $assign->format_grade_for_log($grade),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Test process_save_quick_grades.
+        $sink = $this->redirectEvents();
+
+        $data = array(
+            'grademodified_' . $this->students[0]->id => time(),
+            'quickgrade_' . $this->students[0]->id => '60.0'
+        );
+        $assign->testable_process_save_quick_grades($data);
+        $grade = $assign->get_user_grade($this->students[0]->id, false);
+        $this->assertEquals('60.0', $grade->grade);
+
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($grade->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'grade submission',
+            'view.php?id=' . $assign->get_course_module()->id,
+            $assign->format_grade_for_log($grade),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+
+        // Test update_grade.
+        $sink = $this->redirectEvents();
+        $data = clone($grade);
+        $data->grade = '50.0';
+        $assign->update_grade($data);
+        $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
+        $this->assertEquals('50.0', $grade->grade);
+        $events = $sink->get_events();
+
+        $this->assertCount(1, $events);
+        $event = reset($events);
+        $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($grade->id, $event->objectid);
+        $this->assertEquals($this->students[0]->id, $event->relateduserid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'grade submission',
+            'view.php?id=' . $assign->get_course_module()->id,
+            $assign->format_grade_for_log($grade),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $sink->close();
+    }
+
+    /**
+     * Test the submission_viewed event.
+     */
+    public function test_submission_viewed() {
+        global $PAGE;
+
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+
+        // We need to set the URL in order to view the submission.
+        $PAGE->set_url('/a_url');
+        // A hack - these variables are used by the view_plugin_content function to
+        // determine what we actually want to view - would usually be set in URL.
+        global $_POST;
+        $_POST['plugin'] = 'comments';
+        $_POST['sid'] = $submission->id;
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('viewpluginassignsubmission');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\submission_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($submission->id, $event->objectid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view submission',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewsubmissionforuser', 'assign', $this->students[0]->id),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the feedback_viewed event.
+     */
+    public function test_feedback_viewed() {
+        global $DB, $PAGE;
+
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+        $submission = $assign->get_user_submission($this->students[0]->id, true);
+
+        // Insert a grade for this submission.
+        $grade = new stdClass();
+        $grade->assignment = 1;
+        $grade->userid = $this->students[0]->id;
+        $gradeid = $DB->insert_record('assign_grades', $grade);
+
+        // We need to set the URL in order to view the feedback.
+        $PAGE->set_url('/a_url');
+        // A hack - these variables are used by the view_plugin_content function to
+        // determine what we actually want to view - would usually be set in URL.
+        global $_POST;
+        $_POST['plugin'] = 'comments';
+        $_POST['gid'] = $gradeid;
+        $_POST['sid'] = $submission->id;
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('viewpluginassignfeedback');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\feedback_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEquals($gradeid, $event->objectid);
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view feedback',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewfeedbackforuser', 'assign', $this->students[0]->id),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the feedback_updated event.
+     */
+    public function test_feedback_updated() {
+        $assign = $this->create_instance();
+
+        $logdesc = get_string('feedbackupdate', 'assignfeedback_offline',
+            array('field' => 'The description',
+                  'student' => 'The student\'s name',
+                  'text' => 'Text'));
+        $event = \mod_assign\event\feedback_updated::create(array(
+            'userid' => 2,
+            'relateduserid' => 2,
+            'context' => $assign->get_context(),
+            'other' => array(
+                'assignid' => $assign->get_instance()->id
+            )
+        ));
+        $event->set_legacy_logdata('save grading feedback', $logdesc);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $event->trigger();
+        $events = $sink->get_events();
+        $event = reset($events);
+
+        $this->assertInstanceOf('\mod_assign\event\feedback_updated', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expectedlog = array($assign->get_course()->id, 'assign', 'save grading feedback', 'view.php?id=' . $assign->get_course_module()->id,
+            $logdesc, $assign->get_course_module()->id);
+        $this->assertEventLegacyLogData($expectedlog, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the grading_form_viewed event.
+     */
+    public function test_grading_form_viewed() {
+        global $PAGE;
+
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+
+        // We need to set the URL in order to view the feedback.
+        $PAGE->set_url('/a_url');
+        // A hack - this variable is used by the view_single_grade_page function.
+        global $_POST;
+        $_POST['rownum'] = 1;
+        $_POST['userid'] = $this->students[0]->id;
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('grade');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\grading_form_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view grading form',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewgradingformforstudent', 'assign', array('id' => $this->students[0]->id,
+                'fullname' => fullname($this->students[0]))),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the grading_table_viewed event.
+     */
+    public function test_grading_table_viewed() {
+        global $PAGE;
+
+        $this->setUser($this->editingteachers[0]);
+
+        $assign = $this->create_instance();
+
+        // We need to set the URL in order to view the feedback.
+        $PAGE->set_url('/a_url');
+        // A hack - this variable is used by the view_single_grade_page function.
+        global $_POST;
+        $_POST['rownum'] = 1;
+        $_POST['userid'] = $this->students[0]->id;
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('grading');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\grading_table_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view submission grading table',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewsubmissiongradingtable', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the submission_form_viewed event.
+     */
+    public function test_submission_form_viewed() {
+        global $PAGE;
+
+        $this->setUser($this->students[0]);
+
+        $assign = $this->create_instance();
+
+        // We need to set the URL in order to view the submission form.
+        $PAGE->set_url('/a_url');
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('editsubmission');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\submission_form_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view submit assignment form',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('editsubmission', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the submission_form_viewed event.
+     */
+    public function test_submission_confirmation_form_viewed() {
+        global $PAGE;
+
+        $this->setUser($this->students[0]);
+
+        $assign = $this->create_instance();
+
+        // We need to set the URL in order to view the submission form.
+        $PAGE->set_url('/a_url');
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('submit');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\submission_confirmation_form_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view confirm submit assignment form',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewownsubmissionform', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the reveal_identities_confirmation_page_viewed event.
+     */
+    public function test_reveal_identities_confirmation_page_viewed() {
+        global $PAGE;
+
+        // Set to the admin user so we have the permission to reveal identities.
+        $this->setAdminUser();
+
+        $assign = $this->create_instance();
+
+        // We need to set the URL in order to view the submission form.
+        $PAGE->set_url('/a_url');
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->view('revealidentities');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\reveal_identities_confirmation_page_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewrevealidentitiesconfirm', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the statement_accepted event.
+     */
+    public function test_statement_accepted() {
+        // We want to be a student so we can submit assignments.
+        $this->setUser($this->students[0]);
+
+        // We do not want to send any messages to the student during the PHPUNIT test.
+        set_config('submissionreceipts', false, 'assign');
+
+        $assign = $this->create_instance();
+
+        // Create the data we want to pass to the submit_for_grading function.
+        $data = new stdClass();
+        $data->submissionstatement = 'We are the Borg. You will be assimilated. Resistance is futile. - do you agree
+            to these terms?';
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->submit_for_grading($data, array());
+        $events = $sink->get_events();
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\statement_accepted', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'submission statement accepted',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('submissionstatementacceptedlog',
+                'mod_assign',
+                fullname($this->students[0])),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+
+        // Enable the online text submission plugin.
+        $submissionplugins = $assign->get_submission_plugins();
+        foreach ($submissionplugins as $plugin) {
+            if ($plugin->get_type() === 'onlinetext') {
+                $plugin->enable();
+                break;
+            }
+        }
+
+        // Create the data we want to pass to the save_submission function.
+        $data = new stdClass();
+        $data->onlinetext_editor = array(
+            'text' => 'Online text',
+            'format' => FORMAT_HTML,
+            'itemid' => file_get_unused_draft_itemid()
+        );
+        $data->submissionstatement = 'We are the Borg. You will be assimilated. Resistance is futile. - do you agree
+            to these terms?';
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->save_submission($data, $notices);
+        $events = $sink->get_events();
+        $event = $events[2];
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\statement_accepted', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the batch_set_workflow_state_viewed event.
+     */
+    public function test_batch_set_workflow_state_viewed() {
+        $assign = $this->create_instance();
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->testable_view_batch_set_workflow_state();
+        $events = $sink->get_events();
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\batch_set_workflow_state_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view batch set marking workflow state',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewbatchsetmarkingworkflowstate', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test the batch_set_marker_allocation_viewed event.
+     */
+    public function test_batch_set_marker_allocation_viewed() {
+        $assign = $this->create_instance();
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $assign->testable_view_batch_markingallocation();
+        $events = $sink->get_events();
+        $event = reset($events);
+
+        // Check that the event contains the expected values.
+        $this->assertInstanceOf('\mod_assign\event\batch_set_marker_allocation_viewed', $event);
+        $this->assertEquals($assign->get_context(), $event->get_context());
+        $expected = array(
+            $assign->get_course()->id,
+            'assign',
+            'view batch set marker allocation',
+            'view.php?id=' . $assign->get_course_module()->id,
+            get_string('viewbatchmarkingallocation', 'assign'),
+            $assign->get_course_module()->id
+        );
+        $this->assertEventLegacyLogData($expected, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+}
index ecdddea..0b0c7fe 100644 (file)
@@ -46,3 +46,20 @@ class submission_created extends \mod_assign\event\submission_created {
 class submission_updated extends \mod_assign\event\submission_updated {
 }
 
+/**
+ * mod_assign test class for event base.
+ *
+ * @package    mod_assign
+ * @copyright  2014 Petr Skoda
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class nothing_happened extends \mod_assign\event\base {
+    protected function init() {
+        $this->data['crud'] = 'r';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    public static function get_name() {
+        return 'Nothing happened';
+    }
+}
index 49afbf7..de3103a 100644 (file)
@@ -1147,133 +1147,7 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $this->assertNotEquals(true, strpos($output, $this->students[0]->lastname));
     }
 
-    public function test_extension_granted_event() {
-        $this->setUser($this->editingteachers[0]);
-
-        $tomorrow = time() + 24*60*60;
-        $yesterday = time() - 24*60*60;
-
-        $assign = $this->create_instance(array('duedate' => $yesterday, 'cutoffdate' => $yesterday));
-        $sink = $this->redirectEvents();
-
-        $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\extension_granted', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'grant extension',
-            'view.php?id=' . $assign->get_course_module()->id,
-            $this->students[0]->id,
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-    }
-
-    public function test_submission_locked_event() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
 
-        $assign = $this->create_instance();
-        $sink = $this->redirectEvents();
-
-        $assign->lock_submission($this->students[0]->id);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\submission_locked', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'lock submission',
-            'view.php?id=' . $assign->get_course_module()->id,
-            get_string('locksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
-    }
-
-    public function test_identities_revealed_event() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
-
-        $assign = $this->create_instance(array('blindmarking'=>1));
-        $sink = $this->redirectEvents();
-
-        $assign->reveal_identities();
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\identities_revealed', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'reveal identities',
-            'view.php?id=' . $assign->get_course_module()->id,
-            get_string('revealidentities', 'assign'),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
-    }
-
-    public function test_submission_status_updated_event() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
-
-        $assign = $this->create_instance();
-        $submission = $assign->get_user_submission($this->students[0]->id, true);
-        $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
-        $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
-
-        $sink = $this->redirectEvents();
-        $assign->revert_to_draft($this->students[0]->id);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\submission_status_updated', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($submission->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals(ASSIGN_SUBMISSION_STATUS_DRAFT, $event->other['newstatus']);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'revert submission to draft',
-            'view.php?id=' . $assign->get_course_module()->id,
-            get_string('reverttodraftforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
-    }
 
     public function test_teacher_submit_for_student() {
         global $PAGE;
@@ -1359,199 +1233,6 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
         $sink->close();
     }
 
-    public function test_marker_updated_event() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
-
-        $assign = $this->create_instance();
-
-        $sink = $this->redirectEvents();
-        $assign->testable_process_set_batch_marking_allocation($this->students[0]->id, $this->teachers[0]->id);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\marker_updated', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
-        $this->assertEquals($this->teachers[0]->id, $event->other['markerid']);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'set marking allocation',
-            'view.php?id=' . $assign->get_course_module()->id,
-            get_string('setmarkerallocationforlog', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]), 'marker' => fullname($this->teachers[0]))),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
-    }
-
-    public function test_workflow_state_updated_event() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
-
-        $assign = $this->create_instance();
-
-        $sink = $this->redirectEvents();
-        $assign->testable_process_set_batch_marking_workflow_state($this->students[0]->id, ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $this->assertEquals($this->editingteachers[0]->id, $event->userid);
-        $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW, $event->other['newstate']);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'set marking workflow state',
-            'view.php?id=' . $assign->get_course_module()->id,
-            get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW)),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
-    }
-
-    public function test_submission_duplicated_event() {
-        $this->setUser($this->students[0]);
-
-        $assign = $this->create_instance();
-        $submission1 = $assign->get_user_submission($this->students[0]->id, true, 0);
-        $submission2 = $assign->get_user_submission($this->students[0]->id, true, 1);
-        $submission2->status = ASSIGN_SUBMISSION_STATUS_REOPENED;
-        $assign->testable_update_submission($submission2, $this->students[0]->id, time(), $assign->get_instance()->teamsubmission);
-
-        $sink = $this->redirectEvents();
-        $notices = null;
-        $assign->copy_previous_attempt($notices);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\submission_duplicated', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($submission2->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->userid);
-        $submission2->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'submissioncopied',
-            'view.php?id=' . $assign->get_course_module()->id,
-            $assign->testable_format_submission_for_log($submission2),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-    }
-
-    public function test_submission_unlocked_event() {
-        $this->editingteachers[0]->ignoresesskey = true;
-        $this->setUser($this->editingteachers[0]);
-
-        $assign = $this->create_instance();
-        $sink = $this->redirectEvents();
-
-        $assign->unlock_submission($this->students[0]->id);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\submission_unlocked', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($assign->get_instance()->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'unlock submission',
-            'view.php?id=' . $assign->get_course_module()->id,
-            get_string('unlocksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
-                'fullname' => fullname($this->students[0]))),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Revert to defaults.
-        $this->editingteachers[0]->ignoresesskey = false;
-    }
-
-    public function test_submission_graded_event() {
-        $this->setUser($this->editingteachers[0]);
-        $assign = $this->create_instance();
-
-        // Test apply_grade_to_user.
-        $sink = $this->redirectEvents();
-
-        $data = new stdClass();
-        $data->grade = '50.0';
-        $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
-        $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($grade->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'grade submission',
-            'view.php?id=' . $assign->get_course_module()->id,
-            $assign->format_grade_for_log($grade),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-
-        // Test process_save_quick_grades.
-        $sink = $this->redirectEvents();
-
-        $data = array(
-            'grademodified_' . $this->students[0]->id => time(),
-            'quickgrade_' . $this->students[0]->id => '60.0'
-        );
-        $assign->testable_process_save_quick_grades($data);
-        $grade = $assign->get_user_grade($this->students[0]->id, false);
-        $this->assertEquals('60.0', $grade->grade);
-
-        $events = $sink->get_events();
-        $this->assertCount(1, $events);
-        $event = reset($events);
-        $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
-        $this->assertEquals($assign->get_context(), $event->get_context());
-        $this->assertEquals($grade->id, $event->objectid);
-        $this->assertEquals($this->students[0]->id, $event->relateduserid);
-        $expected = array(
-            $assign->get_course()->id,
-            'assign',
-            'grade submission',
-            'view.php?id=' . $assign->get_course_module()->id,
-            $assign->format_grade_for_log($grade),
-            $assign->get_course_module()->id
-        );
-        $this->assertEventLegacyLogData($expected, $event);
-        $sink->close();
-    }
-
     public function test_disable_submit_after_cutoff_date() {
         global $PAGE;
 
index 5377973..71e6491 100644 (file)
@@ -34,6 +34,27 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class chapter_created extends \core\event\base {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @param \stdClass $chapter
+     * @return chapter_created
+     */
+    public static function create_from_chapter(\stdClass $book, \context_module $context, \stdClass $chapter) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $chapter->id,
+        );
+        /** @var chapter_created $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        $event->add_record_snapshot('book_chapters', $chapter);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
index d882a6b..80ddf71 100644 (file)
@@ -34,13 +34,27 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class chapter_deleted extends \core\event\base {
-
     /**
-     * Legacy log data.
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
      *
-     * @var array
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @param \stdClass $chapter
+     * @return chapter_deleted
      */
-    protected $legacylogdata;
+    public static function create_from_chapter(\stdClass $book, \context_module $context, \stdClass $chapter) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $chapter->id,
+        );
+        /** @var chapter_deleted $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        $event->add_record_snapshot('book_chapters', $chapter);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
@@ -57,7 +71,8 @@ class chapter_deleted extends \core\event\base {
      * @return array|null
      */
     protected function get_legacy_logdata() {
-        return $this->legacylogdata;
+        $chapter = $this->get_record_snapshot('book_chapters', $this->objectid);
+        return array($this->courseid, 'book', 'update', 'view.php?id='.$this->contextinstanceid, $chapter->bookid, $this->contextinstanceid);
     }
 
     /**
@@ -88,14 +103,4 @@ class chapter_deleted extends \core\event\base {
         $this->data['edulevel'] = self::LEVEL_TEACHING;
         $this->data['objecttable'] = 'book_chapters';
     }
-
-    /**
-     * Set the legacy event log data.
-     *
-     * @return array|null
-     */
-    public function set_legacy_logdata($legacydata) {
-        $this->legacylogdata = $legacydata;
-    }
-
 }
index 7293eb4..586d5ae 100644 (file)
@@ -34,6 +34,27 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class chapter_updated extends \core\event\base {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @param \stdClass $chapter
+     * @return chapter_updated
+     */
+    public static function create_from_chapter(\stdClass $book, \context_module $context, \stdClass $chapter) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $chapter->id,
+        );
+        /** @var chapter_updated $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        $event->add_record_snapshot('book_chapters', $chapter);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
index d6d0f8b..8a8dee0 100644 (file)
@@ -34,6 +34,27 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class chapter_viewed extends \core\event\base {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @param \stdClass $chapter
+     * @return chapter_viewed
+     */
+    public static function create_from_chapter(\stdClass $book, \context_module $context, \stdClass $chapter) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $chapter->id,
+        );
+        /** @var chapter_viewed $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        $event->add_record_snapshot('book_chapters', $chapter);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
index a1ad6d7..2216d31 100644 (file)
@@ -34,5 +34,18 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
-}
+    /**
+     * Create the event from course record.
+     *
+     * @param \stdClass $course
+     * @return course_module_instance_list_viewed
+     */
+    public static function create_from_course(\stdClass $course) {
+        $params = array(
+            'context' => \context_course::instance($course->id)
+        );
+        $event = \mod_book\event\course_module_instance_list_viewed::create($params);
+        $event->add_record_snapshot('course', $course);
+        return $event;
+    }}
 
index 19dd67b..af02c7c 100644 (file)
@@ -34,6 +34,25 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class course_module_viewed extends \core\event\course_module_viewed {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @return course_module_viewed
+     */
+    public static function create_from_book(\stdClass $book, \context_module $context) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $book->id
+        );
+        /** @var course_module_viewed $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        return $event;
+    }
 
     /**
      * Init method.
index 02ce6a0..1706147 100644 (file)
@@ -60,14 +60,7 @@ if ($confirm) {  // the operation was confirmed.
             } else if ($found and $ch->subchapter) {
                 $fs->delete_area_files($context->id, 'mod_book', 'chapter', $ch->id);
                 $DB->delete_records('book_chapters', array('id'=>$ch->id));
-
-                $params = array(
-                    'context' => $context,
-                    'objectid' => $ch->id
-                );
-                $event = \mod_book\event\chapter_deleted::create($params);
-                $event->add_record_snapshot('book_chapters', $ch);
-                $event->trigger();
+                \mod_book\event\chapter_deleted::create_from_chapter($book, $context, $ch)->trigger();
             } else if ($found) {
                 break;
             }
@@ -77,15 +70,7 @@ if ($confirm) {  // the operation was confirmed.
     $fs->delete_area_files($context->id, 'mod_book', 'chapter', $chapter->id);
     $DB->delete_records('book_chapters', array('id'=>$chapter->id));
 
-    add_to_log($course->id, 'course', 'update mod', '../mod/book/view.php?id='.$cm->id, 'book '.$book->id);
-    $params = array(
-        'context' => $context,
-        'objectid' => $chapter->id
-    );
-    $event = \mod_book\event\chapter_deleted::create($params);
-    $event->add_record_snapshot('book_chapters', $chapter);
-    $event->set_legacy_logdata(array($course->id, 'book', 'update', 'view.php?id='.$cm->id, $book->id, $cm->id));
-    $event->trigger();
+    \mod_book\event\chapter_deleted::create_from_chapter($book, $context, $chapter)->trigger();
 
     book_preload_chapters($book); // Fix structure.
     $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
index b6ca863..0d0a9af 100644 (file)
@@ -74,18 +74,9 @@ if ($mform->is_cancelled()) {
         $data = file_postupdate_standard_editor($data, 'content', $options, $context, 'mod_book', 'chapter', $data->id);
         $DB->update_record('book_chapters', $data);
         $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
+        $chapter = $DB->get_record('book_chapters', array('id' => $data->id));
 
-        add_to_log($course->id, 'course', 'update mod', '../mod/book/view.php?id='.$cm->id, 'book '.$book->id);
-        $params = array(
-            'context' => $context,
-            'objectid' => $data->id
-        );
-        $event = \mod_book\event\chapter_updated::create($params);
-        foreach ($data as $key => $value) {
-            $chapter->$key = $value;
-        }
-        $event->add_record_snapshot('book_chapters', $chapter);
-        $event->trigger();
+        \mod_book\event\chapter_updated::create_from_chapter($book, $context, $chapter)->trigger();
 
     } else {
         // adding new chapter
@@ -109,15 +100,9 @@ if ($mform->is_cancelled()) {
         $data = file_postupdate_standard_editor($data, 'content', $options, $context, 'mod_book', 'chapter', $data->id);
         $DB->update_record('book_chapters', $data);
         $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
+        $chapter = $DB->get_record('book_chapters', array('id' => $data->id));
 
-        add_to_log($course->id, 'course', 'update mod', '../mod/book/view.php?id='.$cm->id, 'book '.$book->id);
-        $params = array(
-            'context' => $context,
-            'objectid' => $data->id
-        );
-        $event = \mod_book\event\chapter_created::create($params);
-        $event->add_record_snapshot('book_chapters', $data);
-        $event->trigger();
+        \mod_book\event\chapter_created::create_from_chapter($book, $context, $chapter)->trigger();
     }
 
     book_preload_chapters($book); // fix structure
index f58f358..359ecbd 100644 (file)
@@ -47,12 +47,7 @@ $PAGE->set_heading($course->fullname);
 $PAGE->navbar->add($strbooks);
 echo $OUTPUT->header();
 
-$params = array(
-    'context' => context_course::instance($course->id)
-);
-$event = \mod_book\event\course_module_instance_list_viewed::create($params);
-$event->add_record_snapshot('course', $course);
-$event->trigger();
+\mod_book\event\course_module_instance_list_viewed::create_from_course($course)->trigger();
 
 // Get all the appropriate data
 if (!$books = get_all_instances_in_course('book', $course)) {
index dc6a05f..1da5ef7 100644 (file)
@@ -173,22 +173,14 @@ if (!$nothing) {
     foreach ($newchapters as $ch) {
         $ch->pagenum = $i;
         $DB->update_record('book_chapters', $ch);
+        $ch = $DB->get_record('book_chapters', array('id' => $ch->id));
 
-        $params = array(
-            'context' => $context,
-            'objectid' => $ch->id
-        );
-        $event = \mod_book\event\chapter_updated::create($params);
-        $event->trigger();
+        \mod_book\event\chapter_updated::create_from_chapter($book, $context, $ch)->trigger();
 
         $i++;
     }
 }
 
-// MDL-39963 Decide what to do with those logs.
-add_to_log($course->id, 'course', 'update mod', '../mod/book/view.php?id='.$cm->id, 'book '.$book->id);
-add_to_log($course->id, 'book', 'update', 'view.php?id='.$cm->id, $book->id, $cm->id);
-
 book_preload_chapters($book); // fix structure
 $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
 
index 21372f8..d842a46 100644 (file)
@@ -47,42 +47,28 @@ $chapter->hidden = $chapter->hidden ? 0 : 1;
 
 // Update record.
 $DB->update_record('book_chapters', $chapter);
-$params = array(
-    'context' => $context,
-    'objectid' => $chapter->id
-);
-$event = \mod_book\event\chapter_updated::create($params);
-$event->add_record_snapshot('book_chapters', $chapter);
-$event->trigger();
+\mod_book\event\chapter_updated::create_from_chapter($book, $context, $chapter)->trigger();
 
 // Change visibility of subchapters too.
 if (!$chapter->subchapter) {
-    $chapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum', 'id, subchapter, hidden');
+    $chapters = $DB->get_recordset('book_chapters', array('bookid'=>$book->id), 'pagenum ASC');
     $found = 0;
     foreach ($chapters as $ch) {
         if ($ch->id == $chapter->id) {
             $found = 1;
+
         } else if ($found and $ch->subchapter) {
             $ch->hidden = $chapter->hidden;
             $DB->update_record('book_chapters', $ch);
-
-            $params = array(
-                'context' => $context,
-                'objectid' => $ch->id
-            );
-            $event = \mod_book\event\chapter_updated::create($params);
-            $event->trigger();
+            \mod_book\event\chapter_updated::create_from_chapter($book, $context, $ch)->trigger();
 
         } else if ($found) {
             break;
         }
     }
+    $chapters->close();
 }
 
-// MDL-39963 Decide what to do with those logs.
-add_to_log($course->id, 'course', 'update mod', '../mod/book/view.php?id='.$cm->id, 'book '.$book->id);
-add_to_log($course->id, 'book', 'update', 'view.php?id='.$cm->id, $book->id, $cm->id);
-
 book_preload_chapters($book); // fix structure
 $DB->set_field('book', 'revision', $book->revision+1, array('id'=>$book->id));
 
index 2992884..cd95aea 100644 (file)
@@ -47,14 +47,11 @@ class mod_book_events_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course();
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
         $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
+        $context = context_module::instance($book->cmid);
 
         $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $chapter->id
-        );
-        $event = \mod_book\event\chapter_created::create($params);
+        $event = \mod_book\event\chapter_created::create_from_chapter($book, $context, $chapter);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
@@ -80,14 +77,11 @@ class mod_book_events_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course();
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
         $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
+        $context = context_module::instance($book->cmid);
 
         $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $chapter->id
-        );
-        $event = \mod_book\event\chapter_updated::create($params);
+        $event = \mod_book\event\chapter_updated::create_from_chapter($book, $context, $chapter);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
@@ -113,16 +107,12 @@ class mod_book_events_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course();
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
         $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
+        $context = context_module::instance($book->cmid);
 
         $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $chapter->id
-        );
-        $event = \mod_book\event\chapter_deleted::create($params);
-        $event->add_record_snapshot('book_chapters', $chapter);
-        $event->set_legacy_logdata(array('1', 2, false));
+        $event = \mod_book\event\chapter_deleted::create_from_chapter($book, $context, $chapter);
+        $legacy = array($course->id, 'book', 'update', 'view.php?id='.$book->cmid, $book->id, $book->cmid);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
@@ -136,7 +126,7 @@ class mod_book_events_testcase extends advanced_testcase {
         $this->assertEquals(context_module::instance($book->cmid), $event->get_context());
         $this->assertEquals($chapter->id, $event->objectid);
         $this->assertEquals($chapter, $event->get_record_snapshot('book_chapters', $chapter->id));
-        $this->assertEventLegacyLogData(array('1', 2, false), $event);
+        $this->assertEventLegacyLogData($legacy, $event);
         $this->assertEventContextNotUsed($event);
     }
 
@@ -201,14 +191,11 @@ class mod_book_events_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course();
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
         $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
+        $context = context_module::instance($book->cmid);
 
         $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $chapter->id
-        );
-        $event = \mod_book\event\chapter_viewed::create($params);
+        $event = \mod_book\event\chapter_viewed::create_from_chapter($book, $context, $chapter);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
index 6f7dd63..3108576 100644 (file)
@@ -34,6 +34,25 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class book_exported extends \core\event\base {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @return book_exported
+     */
+    public static function create_from_book(\stdClass $book, \context_module $context) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $book->id
+        );
+        /** @var book_exported $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
index d12aa42..f3c4b0d 100644 (file)
@@ -43,13 +43,7 @@ $context = context_module::instance($cm->id);
 require_capability('mod/book:read', $context);
 require_capability('booktool/exportimscp:export', $context);
 
-$params = array(
-    'context' => $context,
-    'objectid' => $book->id
-);
-$event = \booktool_exportimscp\event\book_exported::create($params);
-$event->add_record_snapshot('book', $book);
-$event->trigger();
+\booktool_exportimscp\event\book_exported::create_from_book($book, $context)->trigger();
 
 $file = booktool_exportimscp_build_package($book, $context);
 
index e83d2f1..3132a41 100644 (file)
@@ -46,12 +46,9 @@ class booktool_exportimscp_events_testcase extends advanced_testcase {
 
         $course = $this->getDataGenerator()->create_course();
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
+        $context = context_module::instance($book->cmid);
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $book->id
-        );
-        $event = \booktool_exportimscp\event\book_exported::create($params);
+        $event = \booktool_exportimscp\event\book_exported::create_from_book($book, $context);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
index c34bd30..5ca3e47 100644 (file)
@@ -82,15 +82,10 @@ function toolbook_importhtml_import_chapters($package, $type, $book, $context, $
                 }
 
                 $chapter->id = $DB->insert_record('book_chapters', $chapter);
+                $chapter = $DB->get_record('book_chapters', array('id' => $chapter->id));
                 $chapters[$chapter->id] = $chapter;
 
-                $params = array(
-                    'context' => $context,
-                    'objectid' => $chapter->id
-                );
-                $event = \mod_book\event\chapter_created::create($params);
-                $event->add_record_snapshot('book_chapters', $chapter);
-                $event->trigger();
+                \mod_book\event\chapter_created::create_from_chapter($book, $context, $chapter)->trigger();
             }
         }
     }
@@ -154,7 +149,6 @@ function toolbook_importhtml_import_chapters($package, $type, $book, $context, $
         }
     }
 
-    add_to_log($book->course, 'course', 'update mod', '../mod/book/view.php?id='.$context->instanceid, 'book '.$book->id);
     $fs->delete_area_files($context->id, 'mod_book', 'importhtmltemp', 0);
 
     // update the revision flag - this takes a long time, better to refetch the current value
index ca77d3a..f397d75 100644 (file)
@@ -34,6 +34,25 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class book_printed extends \core\event\base {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @return book_printed
+     */
+    public static function create_from_book(\stdClass $book, \context_module $context) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $book->id
+        );
+        /** @var book_printed $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
index ed1c79f..22cd988 100644 (file)
@@ -34,6 +34,27 @@ defined('MOODLE_INTERNAL') || die();
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class chapter_printed extends \core\event\base {
+    /**
+     * Create instance of event.
+     *
+     * @since Moodle 2.7
+     *
+     * @param \stdClass $book
+     * @param \context_module $context
+     * @param \stdClass $chapter
+     * @return chapter_printed
+     */
+    public static function create_from_chapter(\stdClass $book, \context_module $context, \stdClass $chapter) {
+        $data = array(
+            'context' => $context,
+            'objectid' => $chapter->id,
+        );
+        /** @var chapter_printed $event */
+        $event = self::create($data);
+        $event->add_record_snapshot('book', $book);
+        $event->add_record_snapshot('book_chapters', $chapter);
+        return $event;
+    }
 
     /**
      * Returns description of what happened.
index 9997117..fb83d71 100644 (file)
@@ -76,14 +76,7 @@ if ($chapter) {
     if ($chapter->hidden) {
         require_capability('mod/book:viewhiddenchapters', $context);
     }
-
-    $params = array(
-        'context' => $context,
-        'objectid' => $chapter->id
-    );
-    $event = \booktool_print\event\chapter_printed::create($params);
-    $event->add_record_snapshot('book_chapters', $chapter);
-    $event->trigger();
+    \booktool_print\event\chapter_printed::create_from_chapter($book, $context, $chapter)->trigger();
 
     // page header
     ?>
@@ -129,13 +122,7 @@ if ($chapter) {
     echo '</body> </html>';
 
 } else {
-    $params = array(
-        'context' => $context,
-        'objectid' => $book->id
-    );
-    $event = \booktool_print\event\book_printed::create($params);
-    $event->add_record_snapshot('book', $book);
-    $event->trigger();
+    \booktool_print\event\book_printed::create_from_book($book, $context)->trigger();
 
     $allchapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum');
     $book->intro = file_rewrite_pluginfile_urls($book->intro, 'pluginfile.php', $context->id, 'mod_book', 'intro', null);
index bd3fd7d..da071e5 100644 (file)
@@ -46,12 +46,9 @@ class booktool_print_events_testcase extends advanced_testcase {
 
         $course = $this->getDataGenerator()->create_course();
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
+        $context = context_module::instance($book->cmid);
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $book->id
-        );
-        $event = \booktool_print\event\book_printed::create($params);
+        $event = \booktool_print\event\book_printed::create_from_book($book, $context);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
@@ -78,12 +75,9 @@ class booktool_print_events_testcase extends advanced_testcase {
         $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
         $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
         $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
+        $context = context_module::instance($book->cmid);
 
-        $params = array(
-            'context' => context_module::instance($book->cmid),
-            'objectid' => $chapter->id
-        );
-        $event = \booktool_print\event\chapter_printed::create($params);
+        $event = \booktool_print\event\chapter_printed::create_from_chapter($book, $context, $chapter);
 
         // Triggering and capturing the event.
         $sink = $this->redirectEvents();
diff --git a/mod/book/upgrade.txt b/mod/book/upgrade.txt
new file mode 100644 (file)
index 0000000..27db349
--- /dev/null
@@ -0,0 +1,6 @@
+This files describes API changes in the book code.
+
+=== 2.7 ===
+
+* bogus legacy log calls were removed
+* \mod_book\event\chapter_deleted::set_legacy_logdata() was removed
\ No newline at end of file
index acb7f00..3fd9b45 100644 (file)
@@ -75,15 +75,7 @@ if ($allowedit and !$chapters) {
 }
 // Check chapterid and read chapter data
 if ($chapterid == '0') { // Go to first chapter if no given.
-    $params = array(
-        'context' => $context,
-        'objectid' => $book->id
-    );
-    $event = \mod_book\event\course_module_viewed::create($params);
-    $event->add_record_snapshot('course_modules', $cm);
-    $event->add_record_snapshot('course', $course);
-    $event->add_record_snapshot('book', $book);
-    $event->trigger();
+    \mod_book\event\course_module_viewed::create_from_book($book, $context)->trigger();
 
     foreach ($chapters as $ch) {
         if ($edit) {
@@ -119,13 +111,7 @@ unset($chapterid);
 
 // Security checks END.
 
-$params = array(
-    'context' => $context,
-    'objectid' => $chapter->id
-);
-$event = \mod_book\event\chapter_viewed::create($params);
-$event->add_record_snapshot('book_chapters', $chapter);
-$event->trigger();
+\mod_book\event\chapter_viewed::create_from_chapter($book, $context, $chapter)->trigger();
 
 // Read standard strings.
 $strbooks = get_string('modulenameplural', 'mod_book');
index c8515f0..690ddaf 100644 (file)
@@ -1,20 +1,22 @@
-@mod @mod_forum
+@mod @mod_forum @_file_upload
 Feature: Add forum activities and discussions
   In order to discuss topics with other users
   As a teacher
   I need to add forum activities to moodle courses
 
   @javascript
-  Scenario: Add a forum and a discussion
+  Scenario: Add a forum and a discussion attaching files
     Given the following "users" exist:
       | username | firstname | lastname | email |
       | teacher1 | Teacher | 1 | teacher1@asd.com |
+      | student1 | Student | 1 | student1@asd.com |
     And the following "courses" exist:
       | fullname | shortname | category |
       | Course 1 | C1 | 0 |
     And the following "course enrolments" exist:
       | user | course | role |
       | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
     And I log in as "teacher1"
     And I follow "Course 1"
     And I turn editing mode on
@@ -22,7 +24,24 @@ Feature: Add forum activities and discussions
       | Forum name | Test forum name |
       | Forum type | Standard forum for general use |
       | Description | Test forum description |
-    When I add a new discussion to "Test forum name" forum with:
+    And I add a new discussion to "Test forum name" forum with:
       | Subject | Forum post 1 |
       | Message | This is the body |
-    Then I should see "Test forum name"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    When I add a new discussion to "Test forum name" forum with:
+      | Subject | Post with attachment |
+      | Message | This is the body |
+      | Attachment | lib/tests/fixtures/empty.txt |
+    And I reply "Forum post 1" post from "Test forum name" forum with:
+      | Subject | Reply with attachment |
+      | Message | This is the body |
+      | Attachment | lib/tests/fixtures/upload_users.csv |
+    Then I should see "Reply with attachment"
+    And I should see "upload_users.csv"
+    And I follow "Test forum name"
+    And I follow "Post with attachment"
+    And I should see "empty.txt"
+    And I follow "Edit"
+    And the field "Attachment" matches value "empty.txt"
index cdf25c5..a41c0da 100644 (file)
@@ -328,9 +328,14 @@ class report_log_table_log extends table_sql {
                 $sql = $DB->sql_like('action', ':action', false);
                 $params['action'] = '%'.$action.'%';
             }
-        } else {
+        } else if (!empty($this->filterparams->action)) {
             $sql = "crud = :crud";
             $params['crud'] = $this->filterparams->action;
+        } else {
+            // Add condition for all possible values of crud (to use db index).
+            list($sql, $params) = $DB->get_in_or_equal(array('c', 'r', 'u', 'd'),
+                    SQL_PARAMS_NAMED, 'crud');
+            $sql = "crud ".$sql;
         }
         return array($sql, $params);
     }
@@ -342,10 +347,15 @@ class report_log_table_log extends table_sql {
      * @param bool $useinitialsbar do you want to use the initials bar.
      */
     public function query_db($pagesize, $useinitialsbar = true) {
+        global $DB;
 
         $joins = array();
         $params = array();
 
+        // If we filter by userid and module id we also need to filter by crud and edulevel to ensure DB index is engaged.
+        $useextendeddbindex = !($this->filterparams->logreader instanceof logstore_legacy\log\store)
+                && !empty($this->filterparams->userid) && !empty($this->filterparams->modid);
+
         $groupid = 0;
         if (!empty($this->filterparams->courseid)) {
             if (!empty($this->filterparams->groupid)) {
@@ -362,10 +372,12 @@ class report_log_table_log extends table_sql {
 
         if (!empty($this->filterparams->modid)) {
             $joins[] = "contextinstanceid = :contextinstanceid";
+            $joins[] = "contextlevel = :contextmodule";
             $params['contextinstanceid'] = $this->filterparams->modid;
+            $params['contextmodule'] = CONTEXT_MODULE;
         }
 
-        if (!empty($this->filterparams->action)) {
+        if (!empty($this->filterparams->action) || $useextendeddbindex) {
             list($actionsql, $actionparams) = $this->get_action_sql();
             $joins[] = $actionsql;
             $params = array_merge($params, $actionparams);
@@ -392,6 +404,16 @@ class report_log_table_log extends table_sql {
         if (isset($this->filterparams->edulevel) && ($this->filterparams->edulevel >= 0)) {
             $joins[] = "edulevel = :edulevel";
             $params['edulevel'] = $this->filterparams->edulevel;
+        } else if ($useextendeddbindex) {
+            list($edulevelsql, $edulevelparams) = $DB->get_in_or_equal(array(\core\event\base::LEVEL_OTHER,
+                \core\event\base::LEVEL_PARTICIPATING, \core\event\base::LEVEL_TEACHING), SQL_PARAMS_NAMED, 'edulevel');
+            $joins[] = "edulevel ".$edulevelsql;
+            $params = array_merge($params, $edulevelparams);
+        }
+
+        if (!($this->filterparams->logreader instanceof logstore_legacy\log\store)) {
+            // Filter out anonymous actions, this is N/A for legacy log because it never stores them.
+            $joins[] = "anonymous = 0";
         }
 
         $selector = implode(' AND ', $joins);
index 8ddb193..8d2d37b 100644 (file)
@@ -92,10 +92,13 @@ function report_log_usercourse($userid, $courseid, $coursestart, $logreader = ''
         $logtable = 'log';
         $timefield = 'time';
         $coursefield = 'course';
+        // Anonymous actions are never logged in legacy log.
+        $nonanonymous = '';
     } else {
         $logtable = $reader->get_internal_log_table_name();
         $timefield = 'timecreated';
         $coursefield = 'courseid';
+        $nonanonymous = 'AND anonymous = 0';
     }
 
     $params = array();
@@ -108,7 +111,7 @@ function report_log_usercourse($userid, $courseid, $coursestart, $logreader = ''
     return $DB->get_records_sql("SELECT FLOOR(($timefield - $coursestart)/" . DAYSECS . ") AS day, COUNT(*) AS num
                                    FROM {" . $logtable . "}
                                   WHERE userid = :userid
-                                        AND $timefield > $coursestart $courseselect
+                                        AND $timefield > $coursestart $courseselect $nonanonymous
                                GROUP BY FLOOR(($timefield - $coursestart)/" . DAYSECS .")", $params);
 }
 
@@ -142,10 +145,13 @@ function report_log_userday($userid, $courseid, $daystart, $logreader = '') {
         $logtable = 'log';
         $timefield = 'time';
         $coursefield = 'course';
+        // Anonymous actions are never logged in legacy log.
+        $nonanonymous = '';
     } else {
         $logtable = $reader->get_internal_log_table_name();
         $timefield = 'timecreated';
         $coursefield = 'courseid';
+        $nonanonymous = 'AND anonymous = 0';
     }
     $params = array('userid' => $userid);
 
@@ -157,7 +163,7 @@ function report_log_userday($userid, $courseid, $daystart, $logreader = '') {
     return $DB->get_records_sql("SELECT FLOOR(($timefield - $daystart)/" . HOURSECS . ") AS hour, COUNT(*) AS num
                                    FROM {" . $logtable . "}
                                   WHERE userid = :userid
-                                        AND $timefield > $daystart $courseselect
+                                        AND $timefield > $daystart $courseselect $nonanonymous
                                GROUP BY FLOOR(($timefield - $daystart)/" . HOURSECS . ") ", $params);
 }
 
index fe75bd5..1bcc0e0 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 $string['alfresco_url'] = 'Alfresco URL';
-$string['alfrescourltext'] = 'Afresco API url should be: http://yoursite.com/alfresco/api';
+$string['alfrescourltext'] = 'Afresco API URL should be: http://yoursite.com/alfresco/api or http://yoursite.com/alfresco/soapapi for Alfresco 4.2.d or greater.';
 $string['alfresco:view'] = 'View alfresco repository';
 $string['configplugin'] = 'Alfresco configuration';
 $string['notitle'] = 'notitle';
index ced8bff..0203d73 100644 (file)
@@ -281,11 +281,8 @@ class behat_filepicker extends behat_files {
 
         // The action depends on the field type.
         foreach ($datahash as $locator => $value) {
-            // Getting the node element pointed by the label.
-            $fieldnode = $this->find_field($locator);
 
-            // Gets the field type from a parent node.
-            $field = behat_field_manager::get_form_field($fieldnode, $this->getSession());
+            $field = behat_field_manager::get_form_field_from_label($locator, $this);
 
             // Delegates to the field class.
             $field->set_value($value);
index 48bc155..d5197fd 100644 (file)
@@ -143,11 +143,8 @@ class behat_repository_upload extends behat_files {
 
         // The action depends on the field type.
         foreach ($datahash as $locator => $value) {
-            // Getting the node element pointed by the label.
-            $fieldnode = $this->find_field($locator);
 
-            // Gets the field type from a parent node.
-            $field = behat_field_manager::get_form_field($fieldnode, $this->getSession());
+            $field = behat_field_manager::get_form_field_from_label($locator, $this);
 
             // Delegates to the field class.
             $field->set_value($value);
index 32d2e55..b60d5ad 100644 (file)
@@ -451,9 +451,9 @@ function profile_list_categories() {
  * @param string $redirect
  */
 function profile_edit_category($id, $redirect) {
-    global $DB, $OUTPUT;
+    global $DB, $OUTPUT, $CFG;
 
-    require_once('index_category_form.php');
+    require_once($CFG->dirroot.'/user/profile/index_category_form.php');
     $categoryform = new category_form();
 
     if ($category = $DB->get_record('user_info_category', array('id' => $id))) {
@@ -515,7 +515,7 @@ function profile_edit_field($id, $datatype, $redirect) {
     $field->description = clean_text($field->description, $field->descriptionformat);
     $field->description = array('text' => $field->description, 'format' => $field->descriptionformat, 'itemid' => 0);
 
-    require_once('index_field_form.php');
+    require_once($CFG->dirroot.'/user/profile/index_field_form.php');
     $fieldform = new field_form(null, $field->datatype);
 
     // Convert the data format for.
index c688bb2..6bb4be3 100644 (file)
@@ -108,12 +108,11 @@ switch ($action) {
         // Normal form.
 }
 
-// Print the header.
-echo $OUTPUT->header();
-echo $OUTPUT->heading(get_string('profilefields', 'admin'));
+// Show all categories.
+$categories = $DB->get_records('user_info_category', null, 'sortorder ASC');
 
 // Check that we have at least one category defined.
-if ($DB->count_records('user_info_category') == 0) {
+if (empty($categories)) {
     $defaultcategory = new stdClass();
     $defaultcategory->name = $strdefaultcategory;
     $defaultcategory->sortorder = 1;
@@ -121,8 +120,9 @@ if ($DB->count_records('user_info_category') == 0) {
     redirect($redirect);
 }
 
-// Show all categories.
-$categories = $DB->get_records('user_info_category', null, 'sortorder ASC');
+// Print the header.
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('profilefields', 'admin'));
 
 foreach ($categories as $category) {
     $table = new html_table();
index 9dfdfab..cbdeed8 100644 (file)
--- a/ver