| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 3 | //
 | 
        
           |  |  | 4 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 5 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 6 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 7 | // (at your option) any later version.
 | 
        
           |  |  | 8 | //
 | 
        
           |  |  | 9 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 12 | // GNU General Public License for more details.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 14 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 15 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | /**
 | 
        
           |  |  | 18 |  * @package   mod_data
 | 
        
           |  |  | 19 |  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
 | 
        
           |  |  | 20 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 21 |  */
 | 
        
           |  |  | 22 |   | 
        
           |  |  | 23 | use mod_data\manager;
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 | // Some constants
 | 
        
           |  |  | 28 | define ('DATA_MAX_ENTRIES', 50);
 | 
        
           |  |  | 29 | define ('DATA_PERPAGE_SINGLE', 1);
 | 
        
           |  |  | 30 |   | 
        
           |  |  | 31 | define ('DATA_FIRSTNAME', -1);
 | 
        
           |  |  | 32 | define ('DATA_LASTNAME', -2);
 | 
        
           |  |  | 33 | define ('DATA_APPROVED', -3);
 | 
        
           |  |  | 34 | define ('DATA_TIMEADDED', 0);
 | 
        
           |  |  | 35 | define ('DATA_TIMEMODIFIED', -4);
 | 
        
           |  |  | 36 | define ('DATA_TAGS', -5);
 | 
        
           |  |  | 37 |   | 
        
           |  |  | 38 | define ('DATA_CAP_EXPORT', 'mod/data:viewalluserpresets');
 | 
        
           |  |  | 39 | // Users having assigned the default role "Non-editing teacher" can export database records
 | 
        
           |  |  | 40 | // Using the mod/data capability "viewalluserpresets" existing in Moodle 1.9.x.
 | 
        
           |  |  | 41 | // In Moodle >= 2, new roles may be introduced and used instead.
 | 
        
           |  |  | 42 |   | 
        
           |  |  | 43 | define('DATA_PRESET_COMPONENT', 'mod_data');
 | 
        
           |  |  | 44 | define('DATA_PRESET_FILEAREA', 'site_presets');
 | 
        
           |  |  | 45 | define('DATA_PRESET_CONTEXT', SYSCONTEXTID);
 | 
        
           |  |  | 46 |   | 
        
           |  |  | 47 | define('DATA_EVENT_TYPE_OPEN', 'open');
 | 
        
           |  |  | 48 | define('DATA_EVENT_TYPE_CLOSE', 'close');
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 | require_once(__DIR__ . '/deprecatedlib.php');
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 | /**
 | 
        
           |  |  | 53 |  * @package   mod_data
 | 
        
           |  |  | 54 |  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
 | 
        
           |  |  | 55 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 56 |  */
 | 
        
           |  |  | 57 | class data_field_base {     // Base class for Database Field Types (see field/*/field.class.php)
 | 
        
           |  |  | 58 |   | 
        
           |  |  | 59 |     /** @var string Subclasses must override the type with their name */
 | 
        
           |  |  | 60 |     var $type = 'unknown';
 | 
        
           |  |  | 61 |     /** @var object The database object that this field belongs to */
 | 
        
           |  |  | 62 |     var $data = NULL;
 | 
        
           |  |  | 63 |     /** @var object The field object itself, if we know it */
 | 
        
           |  |  | 64 |     var $field = NULL;
 | 
        
           |  |  | 65 |     /** @var int Width of the icon for this fieldtype */
 | 
        
           |  |  | 66 |     var $iconwidth = 16;
 | 
        
           |  |  | 67 |     /** @var int Width of the icon for this fieldtype */
 | 
        
           |  |  | 68 |     var $iconheight = 16;
 | 
        
           |  |  | 69 |     /** @var object course module or cmifno */
 | 
        
           |  |  | 70 |     var $cm;
 | 
        
           |  |  | 71 |     /** @var object activity context */
 | 
        
           |  |  | 72 |     var $context;
 | 
        
           |  |  | 73 |     /** @var priority for globalsearch indexing */
 | 
        
           |  |  | 74 |     protected static $priority = self::NO_PRIORITY;
 | 
        
           |  |  | 75 |     /** priority value for invalid fields regarding indexing */
 | 
        
           |  |  | 76 |     const NO_PRIORITY = 0;
 | 
        
           |  |  | 77 |     /** priority value for minimum priority */
 | 
        
           |  |  | 78 |     const MIN_PRIORITY = 1;
 | 
        
           |  |  | 79 |     /** priority value for low priority */
 | 
        
           |  |  | 80 |     const LOW_PRIORITY = 2;
 | 
        
           |  |  | 81 |     /** priority value for high priority */
 | 
        
           |  |  | 82 |     const HIGH_PRIORITY = 3;
 | 
        
           |  |  | 83 |     /** priority value for maximum priority */
 | 
        
           |  |  | 84 |     const MAX_PRIORITY = 4;
 | 
        
           |  |  | 85 |   | 
        
           |  |  | 86 |     /** @var bool whether the field is used in preview mode. */
 | 
        
           |  |  | 87 |     protected $preview = false;
 | 
        
           |  |  | 88 |   | 
        
           |  |  | 89 |     /**
 | 
        
           |  |  | 90 |      * Constructor function
 | 
        
           |  |  | 91 |      *
 | 
        
           |  |  | 92 |      * @global object
 | 
        
           |  |  | 93 |      * @uses CONTEXT_MODULE
 | 
        
           |  |  | 94 |      * @param int $field
 | 
        
           |  |  | 95 |      * @param int $data
 | 
        
           |  |  | 96 |      * @param int $cm
 | 
        
           |  |  | 97 |      */
 | 
        
           |  |  | 98 |     function __construct($field=0, $data=0, $cm=0) {   // Field or data or both, each can be id or object
 | 
        
           |  |  | 99 |         global $DB;
 | 
        
           |  |  | 100 |   | 
        
           |  |  | 101 |         if (empty($field) && empty($data)) {
 | 
        
           |  |  | 102 |             throw new \moodle_exception('missingfield', 'data');
 | 
        
           |  |  | 103 |         }
 | 
        
           |  |  | 104 |   | 
        
           |  |  | 105 |         if (!empty($field)) {
 | 
        
           |  |  | 106 |             if (is_object($field)) {
 | 
        
           |  |  | 107 |                 $this->field = $field;  // Programmer knows what they are doing, we hope
 | 
        
           |  |  | 108 |             } else if (!$this->field = $DB->get_record('data_fields', array('id'=>$field))) {
 | 
        
           |  |  | 109 |                 throw new \moodle_exception('invalidfieldid', 'data');
 | 
        
           |  |  | 110 |             }
 | 
        
           |  |  | 111 |             if (empty($data)) {
 | 
        
           |  |  | 112 |                 if (!$this->data = $DB->get_record('data', array('id'=>$this->field->dataid))) {
 | 
        
           |  |  | 113 |                     throw new \moodle_exception('invalidid', 'data');
 | 
        
           |  |  | 114 |                 }
 | 
        
           |  |  | 115 |             }
 | 
        
           |  |  | 116 |         }
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |         if (empty($this->data)) {         // We need to define this properly
 | 
        
           |  |  | 119 |             if (!empty($data)) {
 | 
        
           |  |  | 120 |                 if (is_object($data)) {
 | 
        
           |  |  | 121 |                     $this->data = $data;  // Programmer knows what they are doing, we hope
 | 
        
           |  |  | 122 |                 } else if (!$this->data = $DB->get_record('data', array('id'=>$data))) {
 | 
        
           |  |  | 123 |                     throw new \moodle_exception('invalidid', 'data');
 | 
        
           |  |  | 124 |                 }
 | 
        
           |  |  | 125 |             } else {                      // No way to define it!
 | 
        
           |  |  | 126 |                 throw new \moodle_exception('missingdata', 'data');
 | 
        
           |  |  | 127 |             }
 | 
        
           |  |  | 128 |         }
 | 
        
           |  |  | 129 |   | 
        
           |  |  | 130 |         if ($cm) {
 | 
        
           |  |  | 131 |             $this->cm = $cm;
 | 
        
           |  |  | 132 |         } else {
 | 
        
           |  |  | 133 |             $this->cm = get_coursemodule_from_instance('data', $this->data->id);
 | 
        
           |  |  | 134 |         }
 | 
        
           |  |  | 135 |   | 
        
           |  |  | 136 |         if (empty($this->field)) {         // We need to define some default values
 | 
        
           |  |  | 137 |             $this->define_default_field();
 | 
        
           |  |  | 138 |         }
 | 
        
           |  |  | 139 |   | 
        
           |  |  | 140 |         $this->context = context_module::instance($this->cm->id);
 | 
        
           |  |  | 141 |     }
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |     /**
 | 
        
           |  |  | 144 |      * Return the field type name.
 | 
        
           |  |  | 145 |      *
 | 
        
           |  |  | 146 |      * @return string the filed type.
 | 
        
           |  |  | 147 |      */
 | 
        
           |  |  | 148 |     public function get_name(): string {
 | 
        
           |  |  | 149 |         return $this->field->name;
 | 
        
           |  |  | 150 |     }
 | 
        
           |  |  | 151 |   | 
        
           |  |  | 152 |     /**
 | 
        
           |  |  | 153 |      * Return if the field type supports preview.
 | 
        
           |  |  | 154 |      *
 | 
        
           |  |  | 155 |      * Fields without a preview cannot be displayed in the preset preview.
 | 
        
           |  |  | 156 |      *
 | 
        
           |  |  | 157 |      * @return bool if the plugin supports preview.
 | 
        
           |  |  | 158 |      */
 | 
        
           |  |  | 159 |     public function supports_preview(): bool {
 | 
        
           |  |  | 160 |         return false;
 | 
        
           |  |  | 161 |     }
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |     /**
 | 
        
           |  |  | 164 |      * Generate a fake data_content for this field to be used in preset previews.
 | 
        
           |  |  | 165 |      *
 | 
        
           |  |  | 166 |      * Data plugins must override this method and support_preview in order to enable
 | 
        
           |  |  | 167 |      * preset preview for this field.
 | 
        
           |  |  | 168 |      *
 | 
        
           |  |  | 169 |      * @param int $recordid the fake record id
 | 
        
           |  |  | 170 |      * @return stdClass the fake record
 | 
        
           |  |  | 171 |      */
 | 
        
           |  |  | 172 |     public function get_data_content_preview(int $recordid): stdClass {
 | 
        
           |  |  | 173 |         $message = get_string('nopreviewavailable', 'mod_data', $this->field->name);
 | 
        
           |  |  | 174 |         return (object)[
 | 
        
           |  |  | 175 |             'id' => 0,
 | 
        
           |  |  | 176 |             'fieldid' => $this->field->id,
 | 
        
           |  |  | 177 |             'recordid' => $recordid,
 | 
        
           |  |  | 178 |             'content' => "<span class=\"nopreview\">$message</span>",
 | 
        
           |  |  | 179 |             'content1' => null,
 | 
        
           |  |  | 180 |             'content2' => null,
 | 
        
           |  |  | 181 |             'content3' => null,
 | 
        
           |  |  | 182 |             'content4' => null,
 | 
        
           |  |  | 183 |         ];
 | 
        
           |  |  | 184 |     }
 | 
        
           |  |  | 185 |   | 
        
           |  |  | 186 |     /**
 | 
        
           |  |  | 187 |      * Set the field to preview mode.
 | 
        
           |  |  | 188 |      *
 | 
        
           |  |  | 189 |      * @param bool $preview the new preview value
 | 
        
           |  |  | 190 |      */
 | 
        
           |  |  | 191 |     public function set_preview(bool $preview) {
 | 
        
           |  |  | 192 |         $this->preview = $preview;
 | 
        
           |  |  | 193 |     }
 | 
        
           |  |  | 194 |   | 
        
           |  |  | 195 |     /**
 | 
        
           |  |  | 196 |      * Get the field preview value.
 | 
        
           |  |  | 197 |      *
 | 
        
           |  |  | 198 |      * @return bool
 | 
        
           |  |  | 199 |      */
 | 
        
           |  |  | 200 |     public function get_preview(): bool {
 | 
        
           |  |  | 201 |         return $this->preview;
 | 
        
           |  |  | 202 |     }
 | 
        
           |  |  | 203 |   | 
        
           |  |  | 204 |   | 
        
           |  |  | 205 |     /**
 | 
        
           |  |  | 206 |      * This field just sets up a default field object
 | 
        
           |  |  | 207 |      *
 | 
        
           |  |  | 208 |      * @return bool
 | 
        
           |  |  | 209 |      */
 | 
        
           |  |  | 210 |     function define_default_field() {
 | 
        
           |  |  | 211 |         global $OUTPUT;
 | 
        
           |  |  | 212 |         if (empty($this->data->id)) {
 | 
        
           |  |  | 213 |             echo $OUTPUT->notification('Programmer error: dataid not defined in field class');
 | 
        
           |  |  | 214 |         }
 | 
        
           |  |  | 215 |         $this->field = new stdClass();
 | 
        
           |  |  | 216 |         $this->field->id = 0;
 | 
        
           |  |  | 217 |         $this->field->dataid = $this->data->id;
 | 
        
           |  |  | 218 |         $this->field->type   = $this->type;
 | 
        
           |  |  | 219 |         $this->field->param1 = '';
 | 
        
           |  |  | 220 |         $this->field->param2 = '';
 | 
        
           |  |  | 221 |         $this->field->param3 = '';
 | 
        
           |  |  | 222 |         $this->field->name = '';
 | 
        
           |  |  | 223 |         $this->field->description = '';
 | 
        
           |  |  | 224 |         $this->field->required = false;
 | 
        
           |  |  | 225 |   | 
        
           |  |  | 226 |         return true;
 | 
        
           |  |  | 227 |     }
 | 
        
           |  |  | 228 |   | 
        
           |  |  | 229 |     /**
 | 
        
           |  |  | 230 |      * Set up the field object according to data in an object.  Now is the time to clean it!
 | 
        
           |  |  | 231 |      *
 | 
        
           |  |  | 232 |      * @return bool
 | 
        
           |  |  | 233 |      */
 | 
        
           |  |  | 234 |     function define_field($data) {
 | 
        
           |  |  | 235 |         $this->field->type        = $this->type;
 | 
        
           |  |  | 236 |         $this->field->dataid      = $this->data->id;
 | 
        
           |  |  | 237 |   | 
        
           |  |  | 238 |         $this->field->name        = trim($data->name);
 | 
        
           |  |  | 239 |         $this->field->description = trim($data->description);
 | 
        
           |  |  | 240 |         $this->field->required    = !empty($data->required) ? 1 : 0;
 | 
        
           |  |  | 241 |   | 
        
           |  |  | 242 |         if (isset($data->param1)) {
 | 
        
           |  |  | 243 |             $this->field->param1 = trim($data->param1);
 | 
        
           |  |  | 244 |         }
 | 
        
           |  |  | 245 |         if (isset($data->param2)) {
 | 
        
           |  |  | 246 |             $this->field->param2 = trim($data->param2);
 | 
        
           |  |  | 247 |         }
 | 
        
           |  |  | 248 |         if (isset($data->param3)) {
 | 
        
           |  |  | 249 |             $this->field->param3 = trim($data->param3);
 | 
        
           |  |  | 250 |         }
 | 
        
           |  |  | 251 |         if (isset($data->param4)) {
 | 
        
           |  |  | 252 |             $this->field->param4 = trim($data->param4);
 | 
        
           |  |  | 253 |         }
 | 
        
           |  |  | 254 |         if (isset($data->param5)) {
 | 
        
           |  |  | 255 |             $this->field->param5 = trim($data->param5);
 | 
        
           |  |  | 256 |         }
 | 
        
           |  |  | 257 |   | 
        
           |  |  | 258 |         return true;
 | 
        
           |  |  | 259 |     }
 | 
        
           |  |  | 260 |   | 
        
           |  |  | 261 |     /**
 | 
        
           |  |  | 262 |      * Insert a new field in the database
 | 
        
           |  |  | 263 |      * We assume the field object is already defined as $this->field
 | 
        
           |  |  | 264 |      *
 | 
        
           |  |  | 265 |      * @global object
 | 
        
           |  |  | 266 |      * @return bool
 | 
        
           |  |  | 267 |      */
 | 
        
           |  |  | 268 |     function insert_field() {
 | 
        
           |  |  | 269 |         global $DB, $OUTPUT;
 | 
        
           |  |  | 270 |   | 
        
           |  |  | 271 |         if (empty($this->field)) {
 | 
        
           |  |  | 272 |             echo $OUTPUT->notification('Programmer error: Field has not been defined yet!  See define_field()');
 | 
        
           |  |  | 273 |             return false;
 | 
        
           |  |  | 274 |         }
 | 
        
           |  |  | 275 |   | 
        
           |  |  | 276 |         $this->field->id = $DB->insert_record('data_fields',$this->field);
 | 
        
           |  |  | 277 |   | 
        
           |  |  | 278 |         // Trigger an event for creating this field.
 | 
        
           |  |  | 279 |         $event = \mod_data\event\field_created::create(array(
 | 
        
           |  |  | 280 |             'objectid' => $this->field->id,
 | 
        
           |  |  | 281 |             'context' => $this->context,
 | 
        
           |  |  | 282 |             'other' => array(
 | 
        
           |  |  | 283 |                 'fieldname' => $this->field->name,
 | 
        
           |  |  | 284 |                 'dataid' => $this->data->id
 | 
        
           |  |  | 285 |             )
 | 
        
           |  |  | 286 |         ));
 | 
        
           |  |  | 287 |         $event->trigger();
 | 
        
           |  |  | 288 |   | 
        
           |  |  | 289 |         return true;
 | 
        
           |  |  | 290 |     }
 | 
        
           |  |  | 291 |   | 
        
           |  |  | 292 |   | 
        
           |  |  | 293 |     /**
 | 
        
           |  |  | 294 |      * Update a field in the database
 | 
        
           |  |  | 295 |      *
 | 
        
           |  |  | 296 |      * @global object
 | 
        
           |  |  | 297 |      * @return bool
 | 
        
           |  |  | 298 |      */
 | 
        
           |  |  | 299 |     function update_field() {
 | 
        
           |  |  | 300 |         global $DB;
 | 
        
           |  |  | 301 |   | 
        
           |  |  | 302 |         $DB->update_record('data_fields', $this->field);
 | 
        
           |  |  | 303 |   | 
        
           |  |  | 304 |         // Trigger an event for updating this field.
 | 
        
           |  |  | 305 |         $event = \mod_data\event\field_updated::create(array(
 | 
        
           |  |  | 306 |             'objectid' => $this->field->id,
 | 
        
           |  |  | 307 |             'context' => $this->context,
 | 
        
           |  |  | 308 |             'other' => array(
 | 
        
           |  |  | 309 |                 'fieldname' => $this->field->name,
 | 
        
           |  |  | 310 |                 'dataid' => $this->data->id
 | 
        
           |  |  | 311 |             )
 | 
        
           |  |  | 312 |         ));
 | 
        
           |  |  | 313 |         $event->trigger();
 | 
        
           |  |  | 314 |   | 
        
           |  |  | 315 |         return true;
 | 
        
           |  |  | 316 |     }
 | 
        
           |  |  | 317 |   | 
        
           |  |  | 318 |     /**
 | 
        
           |  |  | 319 |      * Delete a field completely
 | 
        
           |  |  | 320 |      *
 | 
        
           |  |  | 321 |      * @global object
 | 
        
           |  |  | 322 |      * @return bool
 | 
        
           |  |  | 323 |      */
 | 
        
           |  |  | 324 |     function delete_field() {
 | 
        
           |  |  | 325 |         global $DB;
 | 
        
           |  |  | 326 |   | 
        
           |  |  | 327 |         if (!empty($this->field->id)) {
 | 
        
           |  |  | 328 |             $manager = manager::create_from_instance($this->data);
 | 
        
           |  |  | 329 |   | 
        
           |  |  | 330 |             // Get the field before we delete it.
 | 
        
           |  |  | 331 |             $field = $DB->get_record('data_fields', array('id' => $this->field->id));
 | 
        
           |  |  | 332 |   | 
        
           |  |  | 333 |             $this->delete_content();
 | 
        
           |  |  | 334 |             $DB->delete_records('data_fields', array('id'=>$this->field->id));
 | 
        
           |  |  | 335 |   | 
        
           |  |  | 336 |             // Trigger an event for deleting this field.
 | 
        
           |  |  | 337 |             $event = \mod_data\event\field_deleted::create(array(
 | 
        
           |  |  | 338 |                 'objectid' => $this->field->id,
 | 
        
           |  |  | 339 |                 'context' => $this->context,
 | 
        
           |  |  | 340 |                 'other' => array(
 | 
        
           |  |  | 341 |                     'fieldname' => $this->field->name,
 | 
        
           |  |  | 342 |                     'dataid' => $this->data->id
 | 
        
           |  |  | 343 |                  )
 | 
        
           |  |  | 344 |             ));
 | 
        
           |  |  | 345 |   | 
        
           |  |  | 346 |             if (!$manager->has_fields() && $manager->has_records()) {
 | 
        
           |  |  | 347 |                 $DB->delete_records('data_records', ['dataid' => $this->data->id]);
 | 
        
           |  |  | 348 |             }
 | 
        
           |  |  | 349 |   | 
        
           |  |  | 350 |             $event->add_record_snapshot('data_fields', $field);
 | 
        
           |  |  | 351 |             $event->trigger();
 | 
        
           |  |  | 352 |         }
 | 
        
           |  |  | 353 |   | 
        
           |  |  | 354 |         return true;
 | 
        
           |  |  | 355 |     }
 | 
        
           |  |  | 356 |   | 
        
           |  |  | 357 |     /**
 | 
        
           |  |  | 358 |      * Print the relevant form element in the ADD template for this field
 | 
        
           |  |  | 359 |      *
 | 
        
           |  |  | 360 |      * @global object
 | 
        
           |  |  | 361 |      * @param int $recordid
 | 
        
           |  |  | 362 |      * @return string
 | 
        
           |  |  | 363 |      */
 | 
        
           |  |  | 364 |     function display_add_field($recordid=0, $formdata=null) {
 | 
        
           |  |  | 365 |         global $DB, $OUTPUT;
 | 
        
           |  |  | 366 |   | 
        
           |  |  | 367 |         if ($formdata) {
 | 
        
           |  |  | 368 |             $fieldname = 'field_' . $this->field->id;
 | 
        
           |  |  | 369 |             $content = $formdata->$fieldname;
 | 
        
           |  |  | 370 |         } else if ($recordid) {
 | 
        
           |  |  | 371 |             $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
 | 
        
           |  |  | 372 |         } else {
 | 
        
           |  |  | 373 |             $content = '';
 | 
        
           |  |  | 374 |         }
 | 
        
           |  |  | 375 |   | 
        
           |  |  | 376 |         // beware get_field returns false for new, empty records MDL-18567
 | 
        
           |  |  | 377 |         if ($content===false) {
 | 
        
           |  |  | 378 |             $content='';
 | 
        
           |  |  | 379 |         }
 | 
        
           |  |  | 380 |   | 
        
           |  |  | 381 |         $str = '<div title="' . s($this->field->description) . '">';
 | 
        
           |  |  | 382 |         $str .= '<label for="field_'.$this->field->id.'"><span class="accesshide">'.s($this->field->name).'</span>';
 | 
        
           |  |  | 383 |         if ($this->field->required) {
 | 
        
           |  |  | 384 |             $image = $OUTPUT->pix_icon('req', get_string('requiredelement', 'form'));
 | 
        
           |  |  | 385 |             $str .= html_writer::div($image, 'inline-req');
 | 
        
           |  |  | 386 |         }
 | 
        
           |  |  | 387 |         $str .= '</label><input class="basefieldinput form-control d-inline mod-data-input" ' .
 | 
        
           |  |  | 388 |                 'type="text" name="field_' . $this->field->id . '" ' .
 | 
        
           |  |  | 389 |                 'id="field_' . $this->field->id . '" value="' . s($content) . '" />';
 | 
        
           |  |  | 390 |         $str .= '</div>';
 | 
        
           |  |  | 391 |   | 
        
           |  |  | 392 |         return $str;
 | 
        
           |  |  | 393 |     }
 | 
        
           |  |  | 394 |   | 
        
           |  |  | 395 |     /**
 | 
        
           |  |  | 396 |      * Print the relevant form element to define the attributes for this field
 | 
        
           |  |  | 397 |      * viewable by teachers only.
 | 
        
           |  |  | 398 |      *
 | 
        
           |  |  | 399 |      * @global object
 | 
        
           |  |  | 400 |      * @global object
 | 
        
           |  |  | 401 |      * @return void Output is echo'd
 | 
        
           |  |  | 402 |      */
 | 
        
           |  |  | 403 |     function display_edit_field() {
 | 
        
           |  |  | 404 |         global $CFG, $DB, $OUTPUT;
 | 
        
           |  |  | 405 |   | 
        
           |  |  | 406 |         if (empty($this->field)) {   // No field has been defined yet, try and make one
 | 
        
           |  |  | 407 |             $this->define_default_field();
 | 
        
           |  |  | 408 |         }
 | 
        
           |  |  | 409 |   | 
        
           |  |  | 410 |         // Throw an exception if field type doen't exist. Anyway user should never access to edit a field with an unknown fieldtype.
 | 
        
           |  |  | 411 |         if ($this->type === 'unknown') {
 | 
        
           |  |  | 412 |             throw new \moodle_exception(get_string('missingfieldtype', 'data', (object)['name' => $this->field->name]));
 | 
        
           |  |  | 413 |         }
 | 
        
           |  |  | 414 |   | 
        
           |  |  | 415 |         echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
 | 
        
           |  |  | 416 |   | 
        
           |  |  | 417 |         echo '<form id="editfield" action="'.$CFG->wwwroot.'/mod/data/field.php" method="post">'."\n";
 | 
        
           |  |  | 418 |         echo '<input type="hidden" name="d" value="'.$this->data->id.'" />'."\n";
 | 
        
           |  |  | 419 |         if (empty($this->field->id)) {
 | 
        
           |  |  | 420 |             echo '<input type="hidden" name="mode" value="add" />'."\n";
 | 
        
           |  |  | 421 |         } else {
 | 
        
           |  |  | 422 |             echo '<input type="hidden" name="fid" value="'.$this->field->id.'" />'."\n";
 | 
        
           |  |  | 423 |             echo '<input type="hidden" name="mode" value="update" />'."\n";
 | 
        
           |  |  | 424 |         }
 | 
        
           |  |  | 425 |         echo '<input type="hidden" name="type" value="'.$this->type.'" />'."\n";
 | 
        
           |  |  | 426 |         echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />'."\n";
 | 
        
           |  |  | 427 |   | 
        
           |  |  | 428 |         echo $OUTPUT->heading($this->name(), 3);
 | 
        
           |  |  | 429 |   | 
        
           |  |  | 430 |         $filepath = $CFG->dirroot . '/mod/data/field/' . $this->type . '/mod.html';
 | 
        
           |  |  | 431 |         $templatename = 'datafield_' . $this->type . '/' . $this->type;
 | 
        
           |  |  | 432 |   | 
        
           |  |  | 433 |         try {
 | 
        
           |  |  | 434 |             $templatefilepath = \core\output\mustache_template_finder::get_template_filepath($templatename);
 | 
        
           |  |  | 435 |             $templatefileexists = true;
 | 
        
           |  |  | 436 |         } catch (moodle_exception $e) {
 | 
        
           |  |  | 437 |             if (!file_exists($filepath)) {
 | 
        
           |  |  | 438 |                 // Neither file exists.
 | 
        
           |  |  | 439 |                 throw new \moodle_exception(get_string('missingfieldtype', 'data', (object)['name' => $this->field->name]));
 | 
        
           |  |  | 440 |             }
 | 
        
           |  |  | 441 |             $templatefileexists = false;
 | 
        
           |  |  | 442 |         }
 | 
        
           |  |  | 443 |   | 
        
           |  |  | 444 |         if ($templatefileexists) {
 | 
        
           |  |  | 445 |             // Give out templated Bootstrap formatted form fields.
 | 
        
           |  |  | 446 |             $data = $this->get_field_params();
 | 
        
           |  |  | 447 |             echo $OUTPUT->render_from_template($templatename, $data);
 | 
        
           |  |  | 448 |         } else {
 | 
        
           |  |  | 449 |             // Fall back to display mod.html for backward compatibility.
 | 
        
           |  |  | 450 |             require_once($filepath);
 | 
        
           |  |  | 451 |         }
 | 
        
           |  |  | 452 |   | 
        
           |  |  | 453 |         $actionbuttons = html_writer::start_div();
 | 
        
           |  |  | 454 |         $actionbuttons .= html_writer::tag('input', null, [
 | 
        
           |  |  | 455 |             'type' => 'submit',
 | 
        
           |  |  | 456 |             'name' => 'cancel',
 | 
        
           |  |  | 457 |             'value' => get_string('cancel'),
 | 
        
           |  |  | 458 |             'class' => 'btn btn-secondary mx-1'
 | 
        
           |  |  | 459 |         ]);
 | 
        
           |  |  | 460 |         $actionbuttons .= html_writer::tag('input', null, [
 | 
        
           |  |  | 461 |             'type' => 'submit',
 | 
        
           |  |  | 462 |             'value' => get_string('save'),
 | 
        
           |  |  | 463 |             'class' => 'btn btn-primary mx-1'
 | 
        
           |  |  | 464 |         ]);
 | 
        
           |  |  | 465 |         $actionbuttons .= html_writer::end_div();
 | 
        
           |  |  | 466 |   | 
        
           |  |  | 467 |         $stickyfooter = new core\output\sticky_footer($actionbuttons);
 | 
        
           |  |  | 468 |         echo $OUTPUT->render($stickyfooter);
 | 
        
           |  |  | 469 |   | 
        
           |  |  | 470 |         echo '</form>';
 | 
        
           |  |  | 471 |   | 
        
           |  |  | 472 |         echo $OUTPUT->box_end();
 | 
        
           |  |  | 473 |     }
 | 
        
           |  |  | 474 |   | 
        
           |  |  | 475 |     /**
 | 
        
           |  |  | 476 |      * Validates params of fieldinput data. Overwrite to validate fieldtype specific data.
 | 
        
           |  |  | 477 |      *
 | 
        
           |  |  | 478 |      * You are expected to return an array like ['paramname' => 'Error message for paramname param'] if there is an error,
 | 
        
           |  |  | 479 |      * return an empty array if everything is fine.
 | 
        
           |  |  | 480 |      *
 | 
        
           |  |  | 481 |      * @param stdClass $fieldinput The field input data to check
 | 
        
           |  |  | 482 |      * @return array $errors if empty validation was fine, otherwise contains one or more error messages
 | 
        
           |  |  | 483 |      */
 | 
        
           |  |  | 484 |     public function validate(stdClass $fieldinput): array {
 | 
        
           |  |  | 485 |         return [];
 | 
        
           |  |  | 486 |     }
 | 
        
           |  |  | 487 |   | 
        
           |  |  | 488 |     /**
 | 
        
           |  |  | 489 |      * Return the data_content of the field, or generate it if it is in preview mode.
 | 
        
           |  |  | 490 |      *
 | 
        
           |  |  | 491 |      * @param int $recordid the record id
 | 
        
           |  |  | 492 |      * @return stdClass|bool the record data or false if none
 | 
        
           |  |  | 493 |      */
 | 
        
           |  |  | 494 |     protected function get_data_content(int $recordid) {
 | 
        
           |  |  | 495 |         global $DB;
 | 
        
           |  |  | 496 |         if ($this->preview) {
 | 
        
           |  |  | 497 |             return $this->get_data_content_preview($recordid);
 | 
        
           |  |  | 498 |         }
 | 
        
           |  |  | 499 |         return $DB->get_record(
 | 
        
           |  |  | 500 |             'data_content',
 | 
        
           |  |  | 501 |             ['fieldid' => $this->field->id, 'recordid' => $recordid]
 | 
        
           |  |  | 502 |         );
 | 
        
           |  |  | 503 |     }
 | 
        
           |  |  | 504 |   | 
        
           |  |  | 505 |     /**
 | 
        
           |  |  | 506 |      * Display the content of the field in browse mode
 | 
        
           |  |  | 507 |      *
 | 
        
           |  |  | 508 |      * @global object
 | 
        
           |  |  | 509 |      * @param int $recordid
 | 
        
           |  |  | 510 |      * @param object $template
 | 
        
           |  |  | 511 |      * @return bool|string
 | 
        
           |  |  | 512 |      */
 | 
        
           |  |  | 513 |     function display_browse_field($recordid, $template) {
 | 
        
           |  |  | 514 |         $content = $this->get_data_content($recordid);
 | 
        
           |  |  | 515 |         if (!$content || !isset($content->content)) {
 | 
        
           |  |  | 516 |             return '';
 | 
        
           |  |  | 517 |         }
 | 
        
           |  |  | 518 |         $options = new stdClass();
 | 
        
           |  |  | 519 |         if ($this->field->param1 == '1') {
 | 
        
           |  |  | 520 |             // We are autolinking this field, so disable linking within us.
 | 
        
           |  |  | 521 |             $options->filter = false;
 | 
        
           |  |  | 522 |         }
 | 
        
           |  |  | 523 |         $options->para = false;
 | 
        
           | 1441 | ariadna | 524 |         $format = !empty($content->content1) && !empty(trim($content->content1)) ? $content->content1 : null;
 | 
        
           |  |  | 525 |         $str = format_text($content->content, $format, $options);
 | 
        
           | 1 | efrain | 526 |         return $str;
 | 
        
           |  |  | 527 |     }
 | 
        
           |  |  | 528 |   | 
        
           |  |  | 529 |     /**
 | 
        
           |  |  | 530 |      * Update the content of one data field in the data_content table
 | 
        
           |  |  | 531 |      * @global object
 | 
        
           |  |  | 532 |      * @param int $recordid
 | 
        
           |  |  | 533 |      * @param mixed $value
 | 
        
           |  |  | 534 |      * @param string $name
 | 
        
           |  |  | 535 |      * @return bool
 | 
        
           |  |  | 536 |      */
 | 
        
           |  |  | 537 |     function update_content($recordid, $value, $name=''){
 | 
        
           |  |  | 538 |         global $DB;
 | 
        
           |  |  | 539 |   | 
        
           |  |  | 540 |         $content = new stdClass();
 | 
        
           |  |  | 541 |         $content->fieldid = $this->field->id;
 | 
        
           |  |  | 542 |         $content->recordid = $recordid;
 | 
        
           |  |  | 543 |         $content->content = clean_param($value, PARAM_NOTAGS);
 | 
        
           |  |  | 544 |   | 
        
           |  |  | 545 |         if ($oldcontent = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
 | 
        
           |  |  | 546 |             $content->id = $oldcontent->id;
 | 
        
           |  |  | 547 |             return $DB->update_record('data_content', $content);
 | 
        
           |  |  | 548 |         } else {
 | 
        
           |  |  | 549 |             return $DB->insert_record('data_content', $content);
 | 
        
           |  |  | 550 |         }
 | 
        
           |  |  | 551 |     }
 | 
        
           |  |  | 552 |   | 
        
           |  |  | 553 |     /**
 | 
        
           |  |  | 554 |      * Delete all content associated with the field
 | 
        
           |  |  | 555 |      *
 | 
        
           |  |  | 556 |      * @global object
 | 
        
           |  |  | 557 |      * @param int $recordid
 | 
        
           |  |  | 558 |      * @return bool
 | 
        
           |  |  | 559 |      */
 | 
        
           |  |  | 560 |     function delete_content($recordid=0) {
 | 
        
           |  |  | 561 |         global $DB;
 | 
        
           |  |  | 562 |   | 
        
           |  |  | 563 |         if ($recordid) {
 | 
        
           |  |  | 564 |             $conditions = array('fieldid'=>$this->field->id, 'recordid'=>$recordid);
 | 
        
           |  |  | 565 |         } else {
 | 
        
           |  |  | 566 |             $conditions = array('fieldid'=>$this->field->id);
 | 
        
           |  |  | 567 |         }
 | 
        
           |  |  | 568 |   | 
        
           |  |  | 569 |         $rs = $DB->get_recordset('data_content', $conditions);
 | 
        
           |  |  | 570 |         if ($rs->valid()) {
 | 
        
           |  |  | 571 |             $fs = get_file_storage();
 | 
        
           |  |  | 572 |             foreach ($rs as $content) {
 | 
        
           |  |  | 573 |                 $fs->delete_area_files($this->context->id, 'mod_data', 'content', $content->id);
 | 
        
           |  |  | 574 |             }
 | 
        
           |  |  | 575 |         }
 | 
        
           |  |  | 576 |         $rs->close();
 | 
        
           |  |  | 577 |   | 
        
           |  |  | 578 |         return $DB->delete_records('data_content', $conditions);
 | 
        
           |  |  | 579 |     }
 | 
        
           |  |  | 580 |   | 
        
           |  |  | 581 |     /**
 | 
        
           |  |  | 582 |      * Check if a field from an add form is empty
 | 
        
           |  |  | 583 |      *
 | 
        
           |  |  | 584 |      * @param mixed $value
 | 
        
           |  |  | 585 |      * @param mixed $name
 | 
        
           |  |  | 586 |      * @return bool
 | 
        
           |  |  | 587 |      */
 | 
        
           |  |  | 588 |     function notemptyfield($value, $name) {
 | 
        
           |  |  | 589 |         return !empty($value);
 | 
        
           |  |  | 590 |     }
 | 
        
           |  |  | 591 |   | 
        
           |  |  | 592 |     /**
 | 
        
           |  |  | 593 |      * Just in case a field needs to print something before the whole form
 | 
        
           |  |  | 594 |      */
 | 
        
           |  |  | 595 |     function print_before_form() {
 | 
        
           |  |  | 596 |     }
 | 
        
           |  |  | 597 |   | 
        
           |  |  | 598 |     /**
 | 
        
           |  |  | 599 |      * Just in case a field needs to print something after the whole form
 | 
        
           |  |  | 600 |      */
 | 
        
           |  |  | 601 |     function print_after_form() {
 | 
        
           |  |  | 602 |     }
 | 
        
           |  |  | 603 |   | 
        
           |  |  | 604 |   | 
        
           |  |  | 605 |     /**
 | 
        
           |  |  | 606 |      * Returns the sortable field for the content. By default, it's just content
 | 
        
           |  |  | 607 |      * but for some plugins, it could be content 1 - content4
 | 
        
           |  |  | 608 |      *
 | 
        
           |  |  | 609 |      * @return string
 | 
        
           |  |  | 610 |      */
 | 
        
           |  |  | 611 |     function get_sort_field() {
 | 
        
           |  |  | 612 |         return 'content';
 | 
        
           |  |  | 613 |     }
 | 
        
           |  |  | 614 |   | 
        
           |  |  | 615 |     /**
 | 
        
           |  |  | 616 |      * Returns the SQL needed to refer to the column.  Some fields may need to CAST() etc.
 | 
        
           |  |  | 617 |      *
 | 
        
           |  |  | 618 |      * @param string $fieldname
 | 
        
           |  |  | 619 |      * @return string $fieldname
 | 
        
           |  |  | 620 |      */
 | 
        
           |  |  | 621 |     function get_sort_sql($fieldname) {
 | 
        
           |  |  | 622 |         return $fieldname;
 | 
        
           |  |  | 623 |     }
 | 
        
           |  |  | 624 |   | 
        
           |  |  | 625 |     /**
 | 
        
           |  |  | 626 |      * Returns the name/type of the field
 | 
        
           |  |  | 627 |      *
 | 
        
           |  |  | 628 |      * @return string
 | 
        
           |  |  | 629 |      */
 | 
        
           |  |  | 630 |     function name() {
 | 
        
           |  |  | 631 |         return get_string('fieldtypelabel', "datafield_$this->type");
 | 
        
           |  |  | 632 |     }
 | 
        
           |  |  | 633 |   | 
        
           |  |  | 634 |     /**
 | 
        
           |  |  | 635 |      * Prints the respective type icon
 | 
        
           |  |  | 636 |      *
 | 
        
           |  |  | 637 |      * @global object
 | 
        
           |  |  | 638 |      * @return string
 | 
        
           |  |  | 639 |      */
 | 
        
           |  |  | 640 |     function image() {
 | 
        
           |  |  | 641 |         global $OUTPUT;
 | 
        
           |  |  | 642 |   | 
        
           | 1441 | ariadna | 643 |         return $OUTPUT->image_icon('icon', $this->type, 'datafield_' . $this->type);
 | 
        
           | 1 | efrain | 644 |     }
 | 
        
           |  |  | 645 |   | 
        
           |  |  | 646 |     /**
 | 
        
           |  |  | 647 |      * Per default, it is assumed that fields support text exporting.
 | 
        
           |  |  | 648 |      * Override this (return false) on fields not supporting text exporting.
 | 
        
           |  |  | 649 |      *
 | 
        
           |  |  | 650 |      * @return bool true
 | 
        
           |  |  | 651 |      */
 | 
        
           |  |  | 652 |     function text_export_supported() {
 | 
        
           |  |  | 653 |         return true;
 | 
        
           |  |  | 654 |     }
 | 
        
           |  |  | 655 |   | 
        
           |  |  | 656 |     /**
 | 
        
           |  |  | 657 |      * Per default, it is assumed that fields do not support file exporting. Override this (return true)
 | 
        
           |  |  | 658 |      * on fields supporting file export. You will also have to implement export_file_value().
 | 
        
           |  |  | 659 |      *
 | 
        
           |  |  | 660 |      * @return bool true if field will export a file, false otherwise
 | 
        
           |  |  | 661 |      */
 | 
        
           |  |  | 662 |     public function file_export_supported(): bool {
 | 
        
           |  |  | 663 |         return false;
 | 
        
           |  |  | 664 |     }
 | 
        
           |  |  | 665 |   | 
        
           |  |  | 666 |     /**
 | 
        
           |  |  | 667 |      * Per default, does not return a file (just null).
 | 
        
           |  |  | 668 |      * Override this in fields class, if you want your field to export a file content.
 | 
        
           |  |  | 669 |      * In case you are exporting a file value, export_text_value() should return the corresponding file name.
 | 
        
           |  |  | 670 |      *
 | 
        
           |  |  | 671 |      * @param stdClass $record
 | 
        
           |  |  | 672 |      * @return null|string the file content as string or null, if no file content is being provided
 | 
        
           |  |  | 673 |      */
 | 
        
           |  |  | 674 |     public function export_file_value(stdClass $record): null|string {
 | 
        
           |  |  | 675 |         return null;
 | 
        
           |  |  | 676 |     }
 | 
        
           |  |  | 677 |   | 
        
           |  |  | 678 |     /**
 | 
        
           |  |  | 679 |      * Per default, a field does not support the import of files.
 | 
        
           |  |  | 680 |      *
 | 
        
           |  |  | 681 |      * A field type can overwrite this function and return true. In this case it also has to implement the function
 | 
        
           |  |  | 682 |      * import_file_value().
 | 
        
           |  |  | 683 |      *
 | 
        
           |  |  | 684 |      * @return false means file imports are not supported
 | 
        
           |  |  | 685 |      */
 | 
        
           |  |  | 686 |     public function file_import_supported(): bool {
 | 
        
           |  |  | 687 |         return false;
 | 
        
           |  |  | 688 |     }
 | 
        
           |  |  | 689 |   | 
        
           |  |  | 690 |     /**
 | 
        
           |  |  | 691 |      * Returns a stored_file object for exporting a file of a given record.
 | 
        
           |  |  | 692 |      *
 | 
        
           |  |  | 693 |      * @param int $contentid content id
 | 
        
           |  |  | 694 |      * @param string $filecontent the content of the file as string
 | 
        
           |  |  | 695 |      * @param string $filename the filename the file should have
 | 
        
           |  |  | 696 |      */
 | 
        
           |  |  | 697 |     public function import_file_value(int $contentid, string $filecontent, string $filename): void {
 | 
        
           |  |  | 698 |         return;
 | 
        
           |  |  | 699 |     }
 | 
        
           |  |  | 700 |   | 
        
           |  |  | 701 |     /**
 | 
        
           |  |  | 702 |      * Per default, return the record's text value only from the "content" field.
 | 
        
           |  |  | 703 |      * Override this in fields class if necessary.
 | 
        
           |  |  | 704 |      *
 | 
        
           |  |  | 705 |      * @param stdClass $record
 | 
        
           |  |  | 706 |      * @return string
 | 
        
           |  |  | 707 |      */
 | 
        
           |  |  | 708 |     public function export_text_value(stdClass $record) {
 | 
        
           |  |  | 709 |         if ($this->text_export_supported()) {
 | 
        
           |  |  | 710 |             return $record->content;
 | 
        
           |  |  | 711 |         }
 | 
        
           |  |  | 712 |         return '';
 | 
        
           |  |  | 713 |     }
 | 
        
           |  |  | 714 |   | 
        
           |  |  | 715 |     /**
 | 
        
           |  |  | 716 |      * @param string $relativepath
 | 
        
           |  |  | 717 |      * @return bool false
 | 
        
           |  |  | 718 |      */
 | 
        
           |  |  | 719 |     function file_ok($relativepath) {
 | 
        
           |  |  | 720 |         return false;
 | 
        
           |  |  | 721 |     }
 | 
        
           |  |  | 722 |   | 
        
           |  |  | 723 |     /**
 | 
        
           |  |  | 724 |      * Returns the priority for being indexed by globalsearch
 | 
        
           |  |  | 725 |      *
 | 
        
           |  |  | 726 |      * @return int
 | 
        
           |  |  | 727 |      */
 | 
        
           |  |  | 728 |     public static function get_priority() {
 | 
        
           |  |  | 729 |         return static::$priority;
 | 
        
           |  |  | 730 |     }
 | 
        
           |  |  | 731 |   | 
        
           |  |  | 732 |     /**
 | 
        
           |  |  | 733 |      * Returns the presentable string value for a field content.
 | 
        
           |  |  | 734 |      *
 | 
        
           |  |  | 735 |      * The returned string should be plain text.
 | 
        
           |  |  | 736 |      *
 | 
        
           |  |  | 737 |      * @param stdClass $content
 | 
        
           |  |  | 738 |      * @return string
 | 
        
           |  |  | 739 |      */
 | 
        
           |  |  | 740 |     public static function get_content_value($content) {
 | 
        
           |  |  | 741 |         return trim($content->content, "\r\n ");
 | 
        
           |  |  | 742 |     }
 | 
        
           |  |  | 743 |   | 
        
           |  |  | 744 |     /**
 | 
        
           |  |  | 745 |      * Return the plugin configs for external functions,
 | 
        
           |  |  | 746 |      * in some cases the configs will need formatting or be returned only if the current user has some capabilities enabled.
 | 
        
           |  |  | 747 |      *
 | 
        
           |  |  | 748 |      * @return array the list of config parameters
 | 
        
           |  |  | 749 |      * @since Moodle 3.3
 | 
        
           |  |  | 750 |      */
 | 
        
           |  |  | 751 |     public function get_config_for_external() {
 | 
        
           |  |  | 752 |         // Return all the field configs to null (maybe there is a private key for a service or something similar there).
 | 
        
           |  |  | 753 |         $configs = [];
 | 
        
           |  |  | 754 |         for ($i = 1; $i <= 10; $i++) {
 | 
        
           |  |  | 755 |             $configs["param$i"] = null;
 | 
        
           |  |  | 756 |         }
 | 
        
           |  |  | 757 |         return $configs;
 | 
        
           |  |  | 758 |     }
 | 
        
           |  |  | 759 |   | 
        
           |  |  | 760 |     /**
 | 
        
           |  |  | 761 |      * Function to let field define their parameters.
 | 
        
           |  |  | 762 |      *
 | 
        
           |  |  | 763 |      * This method that should be overridden by the datafield plugins
 | 
        
           |  |  | 764 |      * when they need to define their data.
 | 
        
           |  |  | 765 |      *
 | 
        
           |  |  | 766 |      * @return array
 | 
        
           |  |  | 767 |      */
 | 
        
           |  |  | 768 |     protected function get_field_params(): array {
 | 
        
           |  |  | 769 |         // Name and description of the field.
 | 
        
           |  |  | 770 |         $data = [
 | 
        
           |  |  | 771 |             'name' => $this->field->name,
 | 
        
           |  |  | 772 |             'description' => $this->field->description,
 | 
        
           |  |  | 773 |         ];
 | 
        
           |  |  | 774 |   | 
        
           |  |  | 775 |         // Whether the field is required.
 | 
        
           |  |  | 776 |         if (isset($this->field->required)) {
 | 
        
           |  |  | 777 |             $data['required'] = $this->field->required;
 | 
        
           |  |  | 778 |         }
 | 
        
           |  |  | 779 |   | 
        
           |  |  | 780 |         // Add all the field parameters.
 | 
        
           |  |  | 781 |         for ($i = 1; $i <= 10; $i++) {
 | 
        
           |  |  | 782 |             if (isset($this->field->{"param$i"})) {
 | 
        
           |  |  | 783 |                 $data["param$i"] = $this->field->{"param$i"};
 | 
        
           |  |  | 784 |             }
 | 
        
           |  |  | 785 |         }
 | 
        
           |  |  | 786 |   | 
        
           |  |  | 787 |         return $data;
 | 
        
           |  |  | 788 |     }
 | 
        
           |  |  | 789 |   | 
        
           |  |  | 790 | }
 | 
        
           |  |  | 791 |   | 
        
           |  |  | 792 |   | 
        
           |  |  | 793 | /**
 | 
        
           |  |  | 794 |  * Given a template and a dataid, generate a default case template
 | 
        
           |  |  | 795 |  *
 | 
        
           |  |  | 796 |  * @param stdClass $data the mod_data record.
 | 
        
           |  |  | 797 |  * @param string $template the template name
 | 
        
           |  |  | 798 |  * @param int $recordid the entry record
 | 
        
           |  |  | 799 |  * @param bool $form print a form instead of data
 | 
        
           |  |  | 800 |  * @param bool $update if the function update the $data object or not
 | 
        
           |  |  | 801 |  * @return string the template content or an empty string if no content is available (for instance, when database has no fields).
 | 
        
           |  |  | 802 |  */
 | 
        
           |  |  | 803 | function data_generate_default_template(&$data, $template, $recordid = 0, $form = false, $update = true) {
 | 
        
           |  |  | 804 |     global $DB;
 | 
        
           |  |  | 805 |   | 
        
           |  |  | 806 |     if (!$data || !$template) {
 | 
        
           |  |  | 807 |         return '';
 | 
        
           |  |  | 808 |     }
 | 
        
           |  |  | 809 |   | 
        
           |  |  | 810 |     // These templates are empty by default (they have no content).
 | 
        
           |  |  | 811 |     $emptytemplates = [
 | 
        
           |  |  | 812 |         'csstemplate',
 | 
        
           |  |  | 813 |         'jstemplate',
 | 
        
           |  |  | 814 |         'listtemplateheader',
 | 
        
           |  |  | 815 |         'listtemplatefooter',
 | 
        
           |  |  | 816 |         'rsstitletemplate',
 | 
        
           |  |  | 817 |     ];
 | 
        
           |  |  | 818 |     if (in_array($template, $emptytemplates)) {
 | 
        
           |  |  | 819 |         return '';
 | 
        
           |  |  | 820 |     }
 | 
        
           |  |  | 821 |   | 
        
           |  |  | 822 |     $manager = manager::create_from_instance($data);
 | 
        
           |  |  | 823 |     if (empty($manager->get_fields())) {
 | 
        
           |  |  | 824 |         // No template will be returned if there are no fields.
 | 
        
           |  |  | 825 |         return '';
 | 
        
           |  |  | 826 |     }
 | 
        
           |  |  | 827 |   | 
        
           |  |  | 828 |     $templateclass = \mod_data\template::create_default_template($manager, $template, $form);
 | 
        
           |  |  | 829 |     $templatecontent = $templateclass->get_template_content();
 | 
        
           |  |  | 830 |   | 
        
           |  |  | 831 |     if ($update) {
 | 
        
           |  |  | 832 |         // Update the database instance.
 | 
        
           |  |  | 833 |         $newdata = new stdClass();
 | 
        
           |  |  | 834 |         $newdata->id = $data->id;
 | 
        
           |  |  | 835 |         $newdata->{$template} = $templatecontent;
 | 
        
           |  |  | 836 |         $DB->update_record('data', $newdata);
 | 
        
           |  |  | 837 |         $data->{$template} = $templatecontent;
 | 
        
           |  |  | 838 |     }
 | 
        
           |  |  | 839 |   | 
        
           |  |  | 840 |     return $templatecontent;
 | 
        
           |  |  | 841 | }
 | 
        
           |  |  | 842 |   | 
        
           |  |  | 843 | /**
 | 
        
           |  |  | 844 |  * Build the form elements to manage tags for a record.
 | 
        
           |  |  | 845 |  *
 | 
        
           |  |  | 846 |  * @param int|bool $recordid
 | 
        
           |  |  | 847 |  * @param string[] $selected raw tag names
 | 
        
           |  |  | 848 |  * @return string
 | 
        
           |  |  | 849 |  */
 | 
        
           |  |  | 850 | function data_generate_tag_form($recordid = false, $selected = []) {
 | 
        
           |  |  | 851 |     global $CFG, $DB, $OUTPUT, $PAGE;
 | 
        
           |  |  | 852 |   | 
        
           |  |  | 853 |     $tagtypestoshow = \core_tag_area::get_showstandard('mod_data', 'data_records');
 | 
        
           |  |  | 854 |     $showstandard = ($tagtypestoshow != core_tag_tag::HIDE_STANDARD);
 | 
        
           |  |  | 855 |     $typenewtags = ($tagtypestoshow != core_tag_tag::STANDARD_ONLY);
 | 
        
           |  |  | 856 |   | 
        
           |  |  | 857 |     $str = html_writer::start_tag('div', array('class' => 'datatagcontrol'));
 | 
        
           |  |  | 858 |   | 
        
           |  |  | 859 |     $namefield = empty($CFG->keeptagnamecase) ? 'name' : 'rawname';
 | 
        
           |  |  | 860 |   | 
        
           |  |  | 861 |     $tagcollid = \core_tag_area::get_collection('mod_data', 'data_records');
 | 
        
           |  |  | 862 |     $tags = [];
 | 
        
           |  |  | 863 |     $selectedtags = [];
 | 
        
           |  |  | 864 |   | 
        
           |  |  | 865 |     if ($showstandard) {
 | 
        
           |  |  | 866 |         $tags += $DB->get_records_menu('tag', array('isstandard' => 1, 'tagcollid' => $tagcollid),
 | 
        
           |  |  | 867 |             $namefield, 'id,' . $namefield . ' as fieldname');
 | 
        
           |  |  | 868 |     }
 | 
        
           |  |  | 869 |   | 
        
           |  |  | 870 |     if ($recordid) {
 | 
        
           |  |  | 871 |         $selectedtags += core_tag_tag::get_item_tags_array('mod_data', 'data_records', $recordid);
 | 
        
           |  |  | 872 |     }
 | 
        
           |  |  | 873 |   | 
        
           |  |  | 874 |     if (!empty($selected)) {
 | 
        
           |  |  | 875 |         list($sql, $params) = $DB->get_in_or_equal($selected, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 876 |         $params['tagcollid'] = $tagcollid;
 | 
        
           |  |  | 877 |         $sql = "SELECT id, $namefield FROM {tag} WHERE tagcollid = :tagcollid AND rawname $sql";
 | 
        
           |  |  | 878 |         $selectedtags += $DB->get_records_sql_menu($sql, $params);
 | 
        
           |  |  | 879 |     }
 | 
        
           |  |  | 880 |   | 
        
           |  |  | 881 |     $tags += $selectedtags;
 | 
        
           |  |  | 882 |   | 
        
           | 1441 | ariadna | 883 |     $str .= '<select class="form-select" name="tags[]" id="tags" multiple>';
 | 
        
           | 1 | efrain | 884 |     foreach ($tags as $tagid => $tag) {
 | 
        
           |  |  | 885 |         $selected = key_exists($tagid, $selectedtags) ? 'selected' : '';
 | 
        
           |  |  | 886 |         $str .= "<option value='$tag' $selected>$tag</option>";
 | 
        
           |  |  | 887 |     }
 | 
        
           |  |  | 888 |     $str .= '</select>';
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 |     if (has_capability('moodle/tag:manage', context_system::instance()) && $showstandard) {
 | 
        
           |  |  | 891 |         $url = new moodle_url('/tag/manage.php', array('tc' => core_tag_area::get_collection('mod_data',
 | 
        
           |  |  | 892 |             'data_records')));
 | 
        
           |  |  | 893 |         $str .= ' ' . $OUTPUT->action_link($url, get_string('managestandardtags', 'tag'));
 | 
        
           |  |  | 894 |     }
 | 
        
           |  |  | 895 |   | 
        
           |  |  | 896 |     $PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array(
 | 
        
           |  |  | 897 |             '#tags',
 | 
        
           |  |  | 898 |             $typenewtags,
 | 
        
           |  |  | 899 |             '',
 | 
        
           |  |  | 900 |             get_string('entertags', 'tag'),
 | 
        
           |  |  | 901 |             false,
 | 
        
           |  |  | 902 |             $showstandard,
 | 
        
           |  |  | 903 |             get_string('noselection', 'form')
 | 
        
           |  |  | 904 |         )
 | 
        
           |  |  | 905 |     );
 | 
        
           |  |  | 906 |   | 
        
           |  |  | 907 |     $str .= html_writer::end_tag('div');
 | 
        
           |  |  | 908 |   | 
        
           |  |  | 909 |     return $str;
 | 
        
           |  |  | 910 | }
 | 
        
           |  |  | 911 |   | 
        
           |  |  | 912 |   | 
        
           |  |  | 913 | /**
 | 
        
           |  |  | 914 |  * Search for a field name and replaces it with another one in all the
 | 
        
           |  |  | 915 |  * form templates. Set $newfieldname as '' if you want to delete the
 | 
        
           |  |  | 916 |  * field from the form.
 | 
        
           |  |  | 917 |  *
 | 
        
           |  |  | 918 |  * @global object
 | 
        
           |  |  | 919 |  * @param object $data
 | 
        
           |  |  | 920 |  * @param string $searchfieldname
 | 
        
           |  |  | 921 |  * @param string $newfieldname
 | 
        
           |  |  | 922 |  * @return bool
 | 
        
           |  |  | 923 |  */
 | 
        
           |  |  | 924 | function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
 | 
        
           |  |  | 925 |     global $DB;
 | 
        
           |  |  | 926 |   | 
        
           |  |  | 927 |     $newdata = (object)['id' => $data->id];
 | 
        
           |  |  | 928 |     $update = false;
 | 
        
           |  |  | 929 |     $templates = ['listtemplate', 'singletemplate', 'asearchtemplate', 'addtemplate', 'rsstemplate'];
 | 
        
           |  |  | 930 |     foreach ($templates as $templatename) {
 | 
        
           |  |  | 931 |         if (empty($data->$templatename)) {
 | 
        
           |  |  | 932 |             continue;
 | 
        
           |  |  | 933 |         }
 | 
        
           |  |  | 934 |         $search = [
 | 
        
           |  |  | 935 |             '[[' . $searchfieldname . ']]',
 | 
        
           |  |  | 936 |             '[[' . $searchfieldname . '#id]]',
 | 
        
           |  |  | 937 |             '[[' . $searchfieldname . '#name]]',
 | 
        
           |  |  | 938 |             '[[' . $searchfieldname . '#description]]',
 | 
        
           |  |  | 939 |         ];
 | 
        
           |  |  | 940 |         if (empty($newfieldname)) {
 | 
        
           |  |  | 941 |             $replace = ['', '', '', ''];
 | 
        
           |  |  | 942 |         } else {
 | 
        
           |  |  | 943 |             $replace = [
 | 
        
           |  |  | 944 |                 '[[' . $newfieldname . ']]',
 | 
        
           |  |  | 945 |                 '[[' . $newfieldname . '#id]]',
 | 
        
           |  |  | 946 |                 '[[' . $newfieldname . '#name]]',
 | 
        
           |  |  | 947 |                 '[[' . $newfieldname . '#description]]',
 | 
        
           |  |  | 948 |             ];
 | 
        
           |  |  | 949 |         }
 | 
        
           |  |  | 950 |         $newdata->{$templatename} = str_ireplace($search, $replace, $data->{$templatename} ?? '');
 | 
        
           |  |  | 951 |         $update = true;
 | 
        
           |  |  | 952 |     }
 | 
        
           |  |  | 953 |     if (!$update) {
 | 
        
           |  |  | 954 |         return true;
 | 
        
           |  |  | 955 |     }
 | 
        
           |  |  | 956 |     return $DB->update_record('data', $newdata);
 | 
        
           |  |  | 957 | }
 | 
        
           |  |  | 958 |   | 
        
           |  |  | 959 |   | 
        
           |  |  | 960 | /**
 | 
        
           |  |  | 961 |  * Appends a new field at the end of the form template.
 | 
        
           |  |  | 962 |  *
 | 
        
           |  |  | 963 |  * @global object
 | 
        
           |  |  | 964 |  * @param object $data
 | 
        
           |  |  | 965 |  * @param string $newfieldname
 | 
        
           |  |  | 966 |  * @return bool if the field has been added or not
 | 
        
           |  |  | 967 |  */
 | 
        
           |  |  | 968 | function data_append_new_field_to_templates($data, $newfieldname): bool {
 | 
        
           |  |  | 969 |     global $DB, $OUTPUT;
 | 
        
           |  |  | 970 |   | 
        
           |  |  | 971 |     $newdata = (object)['id' => $data->id];
 | 
        
           |  |  | 972 |     $update = false;
 | 
        
           |  |  | 973 |     $templates = ['singletemplate', 'addtemplate', 'rsstemplate'];
 | 
        
           |  |  | 974 |     foreach ($templates as $templatename) {
 | 
        
           |  |  | 975 |         if (empty($data->$templatename)
 | 
        
           |  |  | 976 |             || strpos($data->$templatename, "[[$newfieldname]]") !== false
 | 
        
           |  |  | 977 |             || strpos($data->$templatename, "##otherfields##") !== false
 | 
        
           |  |  | 978 |         ) {
 | 
        
           |  |  | 979 |             continue;
 | 
        
           |  |  | 980 |         }
 | 
        
           |  |  | 981 |         $newdata->$templatename = $data->$templatename;
 | 
        
           |  |  | 982 |         $fields = [[
 | 
        
           |  |  | 983 |             'fieldname' => '[[' . $newfieldname . '#name]]',
 | 
        
           |  |  | 984 |             'fieldcontent' => '[[' . $newfieldname . ']]',
 | 
        
           |  |  | 985 |         ]];
 | 
        
           |  |  | 986 |         $newdata->$templatename .= $OUTPUT->render_from_template(
 | 
        
           |  |  | 987 |             'mod_data/fields_otherfields',
 | 
        
           |  |  | 988 |             ['fields' => $fields, 'classes' => 'added_field']
 | 
        
           |  |  | 989 |         );
 | 
        
           |  |  | 990 |         $update = true;
 | 
        
           |  |  | 991 |     }
 | 
        
           |  |  | 992 |     if (!$update) {
 | 
        
           |  |  | 993 |         return false;
 | 
        
           |  |  | 994 |     }
 | 
        
           |  |  | 995 |     return $DB->update_record('data', $newdata);
 | 
        
           |  |  | 996 | }
 | 
        
           |  |  | 997 |   | 
        
           |  |  | 998 |   | 
        
           |  |  | 999 | /**
 | 
        
           |  |  | 1000 |  * given a field name
 | 
        
           |  |  | 1001 |  * this function creates an instance of the particular subfield class
 | 
        
           |  |  | 1002 |  *
 | 
        
           |  |  | 1003 |  * @global object
 | 
        
           |  |  | 1004 |  * @param string $name
 | 
        
           |  |  | 1005 |  * @param object $data
 | 
        
           |  |  | 1006 |  * @return object|bool
 | 
        
           |  |  | 1007 |  */
 | 
        
           |  |  | 1008 | function data_get_field_from_name($name, $data){
 | 
        
           |  |  | 1009 |     global $DB;
 | 
        
           |  |  | 1010 |   | 
        
           |  |  | 1011 |     $field = $DB->get_record('data_fields', array('name'=>$name, 'dataid'=>$data->id));
 | 
        
           |  |  | 1012 |   | 
        
           |  |  | 1013 |     if ($field) {
 | 
        
           |  |  | 1014 |         return data_get_field($field, $data);
 | 
        
           |  |  | 1015 |     } else {
 | 
        
           |  |  | 1016 |         return false;
 | 
        
           |  |  | 1017 |     }
 | 
        
           |  |  | 1018 | }
 | 
        
           |  |  | 1019 |   | 
        
           |  |  | 1020 | /**
 | 
        
           |  |  | 1021 |  * given a field id
 | 
        
           |  |  | 1022 |  * this function creates an instance of the particular subfield class
 | 
        
           |  |  | 1023 |  *
 | 
        
           |  |  | 1024 |  * @global object
 | 
        
           |  |  | 1025 |  * @param int $fieldid
 | 
        
           |  |  | 1026 |  * @param object $data
 | 
        
           |  |  | 1027 |  * @return bool|object
 | 
        
           |  |  | 1028 |  */
 | 
        
           |  |  | 1029 | function data_get_field_from_id($fieldid, $data){
 | 
        
           |  |  | 1030 |     global $DB;
 | 
        
           |  |  | 1031 |   | 
        
           |  |  | 1032 |     $field = $DB->get_record('data_fields', array('id'=>$fieldid, 'dataid'=>$data->id));
 | 
        
           |  |  | 1033 |   | 
        
           |  |  | 1034 |     if ($field) {
 | 
        
           |  |  | 1035 |         return data_get_field($field, $data);
 | 
        
           |  |  | 1036 |     } else {
 | 
        
           |  |  | 1037 |         return false;
 | 
        
           |  |  | 1038 |     }
 | 
        
           |  |  | 1039 | }
 | 
        
           |  |  | 1040 |   | 
        
           |  |  | 1041 | /**
 | 
        
           |  |  | 1042 |  * given a field id
 | 
        
           |  |  | 1043 |  * this function creates an instance of the particular subfield class
 | 
        
           |  |  | 1044 |  *
 | 
        
           |  |  | 1045 |  * @global object
 | 
        
           |  |  | 1046 |  * @param string $type
 | 
        
           |  |  | 1047 |  * @param object $data
 | 
        
           |  |  | 1048 |  * @return object
 | 
        
           |  |  | 1049 |  */
 | 
        
           |  |  | 1050 | function data_get_field_new($type, $data) {
 | 
        
           |  |  | 1051 |     global $CFG;
 | 
        
           |  |  | 1052 |   | 
        
           |  |  | 1053 |     $type = clean_param($type, PARAM_ALPHA);
 | 
        
           |  |  | 1054 |     $filepath = $CFG->dirroot.'/mod/data/field/'.$type.'/field.class.php';
 | 
        
           |  |  | 1055 |     // It should never access this method if the subfield class doesn't exist.
 | 
        
           |  |  | 1056 |     if (!file_exists($filepath)) {
 | 
        
           |  |  | 1057 |         throw new \moodle_exception('invalidfieldtype', 'data');
 | 
        
           |  |  | 1058 |     }
 | 
        
           |  |  | 1059 |     require_once($filepath);
 | 
        
           |  |  | 1060 |     $newfield = 'data_field_'.$type;
 | 
        
           |  |  | 1061 |     $newfield = new $newfield(0, $data);
 | 
        
           |  |  | 1062 |     return $newfield;
 | 
        
           |  |  | 1063 | }
 | 
        
           |  |  | 1064 |   | 
        
           |  |  | 1065 | /**
 | 
        
           |  |  | 1066 |  * returns a subclass field object given a record of the field, used to
 | 
        
           |  |  | 1067 |  * invoke plugin methods
 | 
        
           |  |  | 1068 |  * input: $param $field - record from db
 | 
        
           |  |  | 1069 |  *
 | 
        
           |  |  | 1070 |  * @global object
 | 
        
           |  |  | 1071 |  * @param stdClass $field the field record
 | 
        
           |  |  | 1072 |  * @param stdClass $data the data instance
 | 
        
           |  |  | 1073 |  * @param stdClass|null $cm optional course module data
 | 
        
           |  |  | 1074 |  * @return data_field_base the field object instance or data_field_base if unkown type
 | 
        
           |  |  | 1075 |  */
 | 
        
           |  |  | 1076 | function data_get_field(stdClass $field, stdClass $data, ?stdClass $cm=null): data_field_base {
 | 
        
           |  |  | 1077 |     global $CFG;
 | 
        
           |  |  | 1078 |     if (!isset($field->type)) {
 | 
        
           |  |  | 1079 |         return new data_field_base($field);
 | 
        
           |  |  | 1080 |     }
 | 
        
           |  |  | 1081 |     $field->type = clean_param($field->type, PARAM_ALPHA);
 | 
        
           |  |  | 1082 |     $filepath = $CFG->dirroot.'/mod/data/field/'.$field->type.'/field.class.php';
 | 
        
           |  |  | 1083 |     if (!file_exists($filepath)) {
 | 
        
           |  |  | 1084 |         return new data_field_base($field);
 | 
        
           |  |  | 1085 |     }
 | 
        
           |  |  | 1086 |     require_once($filepath);
 | 
        
           |  |  | 1087 |     $newfield = 'data_field_'.$field->type;
 | 
        
           |  |  | 1088 |     $newfield = new $newfield($field, $data, $cm);
 | 
        
           |  |  | 1089 |     return $newfield;
 | 
        
           |  |  | 1090 | }
 | 
        
           |  |  | 1091 |   | 
        
           |  |  | 1092 |   | 
        
           |  |  | 1093 | /**
 | 
        
           |  |  | 1094 |  * Given record object (or id), returns true if the record belongs to the current user
 | 
        
           |  |  | 1095 |  *
 | 
        
           |  |  | 1096 |  * @global object
 | 
        
           |  |  | 1097 |  * @global object
 | 
        
           |  |  | 1098 |  * @param mixed $record record object or id
 | 
        
           |  |  | 1099 |  * @return bool
 | 
        
           |  |  | 1100 |  */
 | 
        
           |  |  | 1101 | function data_isowner($record) {
 | 
        
           |  |  | 1102 |     global $USER, $DB;
 | 
        
           |  |  | 1103 |   | 
        
           |  |  | 1104 |     if (!isloggedin()) { // perf shortcut
 | 
        
           |  |  | 1105 |         return false;
 | 
        
           |  |  | 1106 |     }
 | 
        
           |  |  | 1107 |   | 
        
           |  |  | 1108 |     if (!is_object($record)) {
 | 
        
           |  |  | 1109 |         if (!$record = $DB->get_record('data_records', array('id'=>$record))) {
 | 
        
           |  |  | 1110 |             return false;
 | 
        
           |  |  | 1111 |         }
 | 
        
           |  |  | 1112 |     }
 | 
        
           |  |  | 1113 |   | 
        
           |  |  | 1114 |     return ($record->userid == $USER->id);
 | 
        
           |  |  | 1115 | }
 | 
        
           |  |  | 1116 |   | 
        
           |  |  | 1117 | /**
 | 
        
           |  |  | 1118 |  * has a user reached the max number of entries?
 | 
        
           |  |  | 1119 |  *
 | 
        
           |  |  | 1120 |  * @param object $data
 | 
        
           |  |  | 1121 |  * @return bool
 | 
        
           |  |  | 1122 |  */
 | 
        
           |  |  | 1123 | function data_atmaxentries($data){
 | 
        
           |  |  | 1124 |     if (!$data->maxentries){
 | 
        
           |  |  | 1125 |         return false;
 | 
        
           |  |  | 1126 |   | 
        
           |  |  | 1127 |     } else {
 | 
        
           |  |  | 1128 |         return (data_numentries($data) >= $data->maxentries);
 | 
        
           |  |  | 1129 |     }
 | 
        
           |  |  | 1130 | }
 | 
        
           |  |  | 1131 |   | 
        
           |  |  | 1132 | /**
 | 
        
           |  |  | 1133 |  * returns the number of entries already made by this user
 | 
        
           |  |  | 1134 |  *
 | 
        
           |  |  | 1135 |  * @global object
 | 
        
           |  |  | 1136 |  * @global object
 | 
        
           |  |  | 1137 |  * @param object $data
 | 
        
           |  |  | 1138 |  * @return int
 | 
        
           |  |  | 1139 |  */
 | 
        
           |  |  | 1140 | function data_numentries($data, $userid=null) {
 | 
        
           |  |  | 1141 |     global $USER, $DB;
 | 
        
           |  |  | 1142 |     if ($userid === null) {
 | 
        
           |  |  | 1143 |         $userid = $USER->id;
 | 
        
           |  |  | 1144 |     }
 | 
        
           |  |  | 1145 |     $sql = 'SELECT COUNT(*) FROM {data_records} WHERE dataid=? AND userid=?';
 | 
        
           |  |  | 1146 |     return $DB->count_records_sql($sql, array($data->id, $userid));
 | 
        
           |  |  | 1147 | }
 | 
        
           |  |  | 1148 |   | 
        
           |  |  | 1149 | /**
 | 
        
           |  |  | 1150 |  * function that takes in a dataid and adds a record
 | 
        
           |  |  | 1151 |  * this is used everytime an add template is submitted
 | 
        
           |  |  | 1152 |  *
 | 
        
           |  |  | 1153 |  * @global object
 | 
        
           |  |  | 1154 |  * @global object
 | 
        
           |  |  | 1155 |  * @param object $data
 | 
        
           |  |  | 1156 |  * @param int $groupid
 | 
        
           |  |  | 1157 |  * @param int $userid
 | 
        
           |  |  | 1158 |  * @param bool $approved If specified, and the user has the capability to approve entries, then this value
 | 
        
           |  |  | 1159 |  *      will be used as the approved status of the new record
 | 
        
           |  |  | 1160 |  * @return bool
 | 
        
           |  |  | 1161 |  */
 | 
        
           |  |  | 1162 | function data_add_record($data, $groupid = 0, $userid = null, bool $approved = true) {
 | 
        
           |  |  | 1163 |     global $USER, $DB;
 | 
        
           |  |  | 1164 |   | 
        
           |  |  | 1165 |     $cm = get_coursemodule_from_instance('data', $data->id);
 | 
        
           |  |  | 1166 |     $context = context_module::instance($cm->id);
 | 
        
           |  |  | 1167 |   | 
        
           |  |  | 1168 |     $record = new stdClass();
 | 
        
           |  |  | 1169 |     $record->userid = $userid ?? $USER->id;
 | 
        
           |  |  | 1170 |     $record->dataid = $data->id;
 | 
        
           |  |  | 1171 |     $record->groupid = $groupid;
 | 
        
           |  |  | 1172 |     $record->timecreated = $record->timemodified = time();
 | 
        
           |  |  | 1173 |     if (has_capability('mod/data:approve', $context)) {
 | 
        
           |  |  | 1174 |         $record->approved = $approved;
 | 
        
           |  |  | 1175 |     } else {
 | 
        
           |  |  | 1176 |         $record->approved = 0;
 | 
        
           |  |  | 1177 |     }
 | 
        
           |  |  | 1178 |     $record->id = $DB->insert_record('data_records', $record);
 | 
        
           |  |  | 1179 |   | 
        
           |  |  | 1180 |     // Trigger an event for creating this record.
 | 
        
           |  |  | 1181 |     $event = \mod_data\event\record_created::create(array(
 | 
        
           |  |  | 1182 |         'objectid' => $record->id,
 | 
        
           |  |  | 1183 |         'context' => $context,
 | 
        
           |  |  | 1184 |         'other' => array(
 | 
        
           |  |  | 1185 |             'dataid' => $data->id
 | 
        
           |  |  | 1186 |         )
 | 
        
           |  |  | 1187 |     ));
 | 
        
           |  |  | 1188 |     $event->trigger();
 | 
        
           |  |  | 1189 |   | 
        
           |  |  | 1190 |     $course = get_course($cm->course);
 | 
        
           |  |  | 1191 |     data_update_completion_state($data, $course, $cm);
 | 
        
           |  |  | 1192 |   | 
        
           |  |  | 1193 |     return $record->id;
 | 
        
           |  |  | 1194 | }
 | 
        
           |  |  | 1195 |   | 
        
           |  |  | 1196 | /**
 | 
        
           |  |  | 1197 |  * check the multple existence any tag in a template
 | 
        
           |  |  | 1198 |  *
 | 
        
           |  |  | 1199 |  * check to see if there are 2 or more of the same tag being used.
 | 
        
           |  |  | 1200 |  *
 | 
        
           |  |  | 1201 |  * @global object
 | 
        
           |  |  | 1202 |  * @param int $dataid,
 | 
        
           |  |  | 1203 |  * @param string $template
 | 
        
           |  |  | 1204 |  * @return bool
 | 
        
           |  |  | 1205 |  */
 | 
        
           |  |  | 1206 | function data_tags_check($dataid, $template) {
 | 
        
           |  |  | 1207 |     global $DB, $OUTPUT;
 | 
        
           |  |  | 1208 |   | 
        
           |  |  | 1209 |     // first get all the possible tags
 | 
        
           |  |  | 1210 |     $fields = $DB->get_records('data_fields', array('dataid'=>$dataid));
 | 
        
           |  |  | 1211 |     // then we generate strings to replace
 | 
        
           |  |  | 1212 |     $tagsok = true; // let's be optimistic
 | 
        
           |  |  | 1213 |     foreach ($fields as $field){
 | 
        
           |  |  | 1214 |         $pattern="/\[\[" . preg_quote($field->name, '/') . "\]\]/i";
 | 
        
           |  |  | 1215 |         if (preg_match_all($pattern, $template, $dummy)>1){
 | 
        
           |  |  | 1216 |             $tagsok = false;
 | 
        
           |  |  | 1217 |             echo $OUTPUT->notification('[['.$field->name.']] - '.get_string('multipletags','data'));
 | 
        
           |  |  | 1218 |         }
 | 
        
           |  |  | 1219 |     }
 | 
        
           |  |  | 1220 |     // else return true
 | 
        
           |  |  | 1221 |     return $tagsok;
 | 
        
           |  |  | 1222 | }
 | 
        
           |  |  | 1223 |   | 
        
           |  |  | 1224 | /**
 | 
        
           |  |  | 1225 |  * Adds an instance of a data
 | 
        
           |  |  | 1226 |  *
 | 
        
           |  |  | 1227 |  * @param stdClass $data
 | 
        
           |  |  | 1228 |  * @param mod_data_mod_form $mform
 | 
        
           |  |  | 1229 |  * @return int intance id
 | 
        
           |  |  | 1230 |  */
 | 
        
           |  |  | 1231 | function data_add_instance($data, $mform = null) {
 | 
        
           |  |  | 1232 |     global $DB, $CFG;
 | 
        
           |  |  | 1233 |     require_once($CFG->dirroot.'/mod/data/locallib.php');
 | 
        
           |  |  | 1234 |   | 
        
           |  |  | 1235 |     if (empty($data->assessed)) {
 | 
        
           |  |  | 1236 |         $data->assessed = 0;
 | 
        
           |  |  | 1237 |     }
 | 
        
           |  |  | 1238 |   | 
        
           |  |  | 1239 |     if (empty($data->ratingtime) || empty($data->assessed)) {
 | 
        
           |  |  | 1240 |         $data->assesstimestart  = 0;
 | 
        
           |  |  | 1241 |         $data->assesstimefinish = 0;
 | 
        
           |  |  | 1242 |     }
 | 
        
           |  |  | 1243 |   | 
        
           |  |  | 1244 |     $data->timemodified = time();
 | 
        
           |  |  | 1245 |   | 
        
           |  |  | 1246 |     $data->id = $DB->insert_record('data', $data);
 | 
        
           |  |  | 1247 |   | 
        
           |  |  | 1248 |     // Add calendar events if necessary.
 | 
        
           |  |  | 1249 |     data_set_events($data);
 | 
        
           |  |  | 1250 |     if (!empty($data->completionexpected)) {
 | 
        
           |  |  | 1251 |         \core_completion\api::update_completion_date_event($data->coursemodule, 'data', $data->id, $data->completionexpected);
 | 
        
           |  |  | 1252 |     }
 | 
        
           |  |  | 1253 |   | 
        
           |  |  | 1254 |     data_grade_item_update($data);
 | 
        
           |  |  | 1255 |   | 
        
           |  |  | 1256 |     return $data->id;
 | 
        
           |  |  | 1257 | }
 | 
        
           |  |  | 1258 |   | 
        
           |  |  | 1259 | /**
 | 
        
           |  |  | 1260 |  * updates an instance of a data
 | 
        
           |  |  | 1261 |  *
 | 
        
           |  |  | 1262 |  * @global object
 | 
        
           |  |  | 1263 |  * @param object $data
 | 
        
           |  |  | 1264 |  * @return bool
 | 
        
           |  |  | 1265 |  */
 | 
        
           |  |  | 1266 | function data_update_instance($data) {
 | 
        
           |  |  | 1267 |     global $DB, $CFG;
 | 
        
           |  |  | 1268 |     require_once($CFG->dirroot.'/mod/data/locallib.php');
 | 
        
           |  |  | 1269 |   | 
        
           |  |  | 1270 |     $data->timemodified = time();
 | 
        
           |  |  | 1271 |     if (!empty($data->instance)) {
 | 
        
           |  |  | 1272 |         $data->id = $data->instance;
 | 
        
           |  |  | 1273 |     }
 | 
        
           |  |  | 1274 |   | 
        
           |  |  | 1275 |     if (empty($data->assessed)) {
 | 
        
           |  |  | 1276 |         $data->assessed = 0;
 | 
        
           |  |  | 1277 |     }
 | 
        
           |  |  | 1278 |   | 
        
           |  |  | 1279 |     if (empty($data->ratingtime) or empty($data->assessed)) {
 | 
        
           |  |  | 1280 |         $data->assesstimestart  = 0;
 | 
        
           |  |  | 1281 |         $data->assesstimefinish = 0;
 | 
        
           |  |  | 1282 |     }
 | 
        
           |  |  | 1283 |   | 
        
           |  |  | 1284 |     if (empty($data->notification)) {
 | 
        
           |  |  | 1285 |         $data->notification = 0;
 | 
        
           |  |  | 1286 |     }
 | 
        
           |  |  | 1287 |   | 
        
           |  |  | 1288 |     $DB->update_record('data', $data);
 | 
        
           |  |  | 1289 |   | 
        
           |  |  | 1290 |     // Add calendar events if necessary.
 | 
        
           |  |  | 1291 |     data_set_events($data);
 | 
        
           |  |  | 1292 |     $completionexpected = (!empty($data->completionexpected)) ? $data->completionexpected : null;
 | 
        
           |  |  | 1293 |     \core_completion\api::update_completion_date_event($data->coursemodule, 'data', $data->id, $completionexpected);
 | 
        
           |  |  | 1294 |   | 
        
           |  |  | 1295 |     data_grade_item_update($data);
 | 
        
           |  |  | 1296 |   | 
        
           |  |  | 1297 |     return true;
 | 
        
           |  |  | 1298 |   | 
        
           |  |  | 1299 | }
 | 
        
           |  |  | 1300 |   | 
        
           |  |  | 1301 | /**
 | 
        
           |  |  | 1302 |  * deletes an instance of a data
 | 
        
           |  |  | 1303 |  *
 | 
        
           |  |  | 1304 |  * @global object
 | 
        
           |  |  | 1305 |  * @param int $id
 | 
        
           |  |  | 1306 |  * @return bool
 | 
        
           |  |  | 1307 |  */
 | 
        
           |  |  | 1308 | function data_delete_instance($id) {    // takes the dataid
 | 
        
           |  |  | 1309 |     global $DB, $CFG;
 | 
        
           |  |  | 1310 |   | 
        
           |  |  | 1311 |     if (!$data = $DB->get_record('data', array('id'=>$id))) {
 | 
        
           |  |  | 1312 |         return false;
 | 
        
           |  |  | 1313 |     }
 | 
        
           |  |  | 1314 |   | 
        
           |  |  | 1315 |     $cm = get_coursemodule_from_instance('data', $data->id);
 | 
        
           |  |  | 1316 |     $context = context_module::instance($cm->id);
 | 
        
           |  |  | 1317 |   | 
        
           |  |  | 1318 |     // Delete all information related to fields.
 | 
        
           |  |  | 1319 |     $fields = $DB->get_records('data_fields', ['dataid' => $id]);
 | 
        
           |  |  | 1320 |     foreach ($fields as $field) {
 | 
        
           |  |  | 1321 |         $todelete = data_get_field($field, $data, $cm);
 | 
        
           |  |  | 1322 |         $todelete->delete_field();
 | 
        
           |  |  | 1323 |     }
 | 
        
           |  |  | 1324 |   | 
        
           |  |  | 1325 |     // Remove old calendar events.
 | 
        
           |  |  | 1326 |     $events = $DB->get_records('event', array('modulename' => 'data', 'instance' => $id));
 | 
        
           |  |  | 1327 |     foreach ($events as $event) {
 | 
        
           |  |  | 1328 |         $event = calendar_event::load($event);
 | 
        
           |  |  | 1329 |         $event->delete();
 | 
        
           |  |  | 1330 |     }
 | 
        
           |  |  | 1331 |   | 
        
           |  |  | 1332 |     // cleanup gradebook
 | 
        
           |  |  | 1333 |     data_grade_item_delete($data);
 | 
        
           |  |  | 1334 |   | 
        
           |  |  | 1335 |     // Delete the instance itself
 | 
        
           |  |  | 1336 |     // We must delete the module record after we delete the grade item.
 | 
        
           |  |  | 1337 |     $result = $DB->delete_records('data', array('id'=>$id));
 | 
        
           |  |  | 1338 |   | 
        
           |  |  | 1339 |     return $result;
 | 
        
           |  |  | 1340 | }
 | 
        
           |  |  | 1341 |   | 
        
           |  |  | 1342 | /**
 | 
        
           |  |  | 1343 |  * returns a summary of data activity of this user
 | 
        
           |  |  | 1344 |  *
 | 
        
           |  |  | 1345 |  * @global object
 | 
        
           |  |  | 1346 |  * @param object $course
 | 
        
           |  |  | 1347 |  * @param object $user
 | 
        
           |  |  | 1348 |  * @param object $mod
 | 
        
           |  |  | 1349 |  * @param object $data
 | 
        
           |  |  | 1350 |  * @return object|null
 | 
        
           |  |  | 1351 |  */
 | 
        
           |  |  | 1352 | function data_user_outline($course, $user, $mod, $data) {
 | 
        
           |  |  | 1353 |     global $DB, $CFG;
 | 
        
           |  |  | 1354 |     require_once("$CFG->libdir/gradelib.php");
 | 
        
           |  |  | 1355 |   | 
        
           |  |  | 1356 |     $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
 | 
        
           |  |  | 1357 |     if (empty($grades->items[0]->grades)) {
 | 
        
           |  |  | 1358 |         $grade = false;
 | 
        
           |  |  | 1359 |     } else {
 | 
        
           |  |  | 1360 |         $grade = reset($grades->items[0]->grades);
 | 
        
           |  |  | 1361 |     }
 | 
        
           |  |  | 1362 |   | 
        
           |  |  | 1363 |   | 
        
           |  |  | 1364 |     if ($countrecords = $DB->count_records('data_records', array('dataid'=>$data->id, 'userid'=>$user->id))) {
 | 
        
           |  |  | 1365 |         $result = new stdClass();
 | 
        
           |  |  | 1366 |         $result->info = get_string('numrecords', 'data', $countrecords);
 | 
        
           |  |  | 1367 |         $lastrecord   = $DB->get_record_sql('SELECT id,timemodified FROM {data_records}
 | 
        
           |  |  | 1368 |                                               WHERE dataid = ? AND userid = ?
 | 
        
           |  |  | 1369 |                                            ORDER BY timemodified DESC', array($data->id, $user->id), true);
 | 
        
           |  |  | 1370 |         $result->time = $lastrecord->timemodified;
 | 
        
           |  |  | 1371 |         if ($grade) {
 | 
        
           |  |  | 1372 |             if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
 | 
        
           |  |  | 1373 |                 $result->info .= ', ' . get_string('gradenoun') . ': ' . $grade->str_long_grade;
 | 
        
           |  |  | 1374 |             } else {
 | 
        
           |  |  | 1375 |                 $result->info = get_string('gradenoun') . ': ' . get_string('hidden', 'grades');
 | 
        
           |  |  | 1376 |             }
 | 
        
           |  |  | 1377 |         }
 | 
        
           |  |  | 1378 |         return $result;
 | 
        
           |  |  | 1379 |     } else if ($grade) {
 | 
        
           |  |  | 1380 |         $result = (object) [
 | 
        
           |  |  | 1381 |             'time' => grade_get_date_for_user_grade($grade, $user),
 | 
        
           |  |  | 1382 |         ];
 | 
        
           |  |  | 1383 |         if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
 | 
        
           |  |  | 1384 |             $result->info = get_string('gradenoun') . ': ' . $grade->str_long_grade;
 | 
        
           |  |  | 1385 |         } else {
 | 
        
           |  |  | 1386 |             $result->info = get_string('gradenoun') . ': ' . get_string('hidden', 'grades');
 | 
        
           |  |  | 1387 |         }
 | 
        
           |  |  | 1388 |   | 
        
           |  |  | 1389 |         return $result;
 | 
        
           |  |  | 1390 |     }
 | 
        
           |  |  | 1391 |     return NULL;
 | 
        
           |  |  | 1392 | }
 | 
        
           |  |  | 1393 |   | 
        
           |  |  | 1394 | /**
 | 
        
           |  |  | 1395 |  * Prints all the records uploaded by this user
 | 
        
           |  |  | 1396 |  *
 | 
        
           |  |  | 1397 |  * @global object
 | 
        
           |  |  | 1398 |  * @param object $course
 | 
        
           |  |  | 1399 |  * @param object $user
 | 
        
           |  |  | 1400 |  * @param object $mod
 | 
        
           |  |  | 1401 |  * @param object $data
 | 
        
           |  |  | 1402 |  */
 | 
        
           |  |  | 1403 | function data_user_complete($course, $user, $mod, $data) {
 | 
        
           |  |  | 1404 |     global $DB, $CFG, $OUTPUT;
 | 
        
           |  |  | 1405 |     require_once("$CFG->libdir/gradelib.php");
 | 
        
           |  |  | 1406 |   | 
        
           |  |  | 1407 |     $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
 | 
        
           |  |  | 1408 |     if (!empty($grades->items[0]->grades)) {
 | 
        
           |  |  | 1409 |         $grade = reset($grades->items[0]->grades);
 | 
        
           |  |  | 1410 |         if (!$grade->hidden || has_capability('moodle/grade:viewhidden', context_course::instance($course->id))) {
 | 
        
           |  |  | 1411 |             echo $OUTPUT->container(get_string('gradenoun') . ': ' . $grade->str_long_grade);
 | 
        
           |  |  | 1412 |             if ($grade->str_feedback) {
 | 
        
           |  |  | 1413 |                 echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
 | 
        
           |  |  | 1414 |             }
 | 
        
           |  |  | 1415 |         } else {
 | 
        
           |  |  | 1416 |             echo $OUTPUT->container(get_string('gradenoun') . ': ' . get_string('hidden', 'grades'));
 | 
        
           |  |  | 1417 |         }
 | 
        
           |  |  | 1418 |     }
 | 
        
           |  |  | 1419 |     $records = $DB->get_records(
 | 
        
           |  |  | 1420 |         'data_records',
 | 
        
           |  |  | 1421 |         ['dataid' => $data->id, 'userid' => $user->id],
 | 
        
           |  |  | 1422 |         'timemodified DESC'
 | 
        
           |  |  | 1423 |     );
 | 
        
           |  |  | 1424 |     if ($records) {
 | 
        
           |  |  | 1425 |         $manager = manager::create_from_instance($data);
 | 
        
           |  |  | 1426 |         $parser = $manager->get_template('singletemplate');
 | 
        
           |  |  | 1427 |         echo $parser->parse_entries($records);
 | 
        
           |  |  | 1428 |     }
 | 
        
           |  |  | 1429 | }
 | 
        
           |  |  | 1430 |   | 
        
           |  |  | 1431 | /**
 | 
        
           |  |  | 1432 |  * Return grade for given user or all users.
 | 
        
           |  |  | 1433 |  *
 | 
        
           |  |  | 1434 |  * @global object
 | 
        
           |  |  | 1435 |  * @param object $data
 | 
        
           |  |  | 1436 |  * @param int $userid optional user id, 0 means all users
 | 
        
           |  |  | 1437 |  * @return array array of grades, false if none
 | 
        
           |  |  | 1438 |  */
 | 
        
           |  |  | 1439 | function data_get_user_grades($data, $userid=0) {
 | 
        
           |  |  | 1440 |     global $CFG;
 | 
        
           |  |  | 1441 |   | 
        
           |  |  | 1442 |     require_once($CFG->dirroot.'/rating/lib.php');
 | 
        
           |  |  | 1443 |   | 
        
           |  |  | 1444 |     $ratingoptions = new stdClass;
 | 
        
           |  |  | 1445 |     $ratingoptions->component = 'mod_data';
 | 
        
           |  |  | 1446 |     $ratingoptions->ratingarea = 'entry';
 | 
        
           |  |  | 1447 |     $ratingoptions->modulename = 'data';
 | 
        
           |  |  | 1448 |     $ratingoptions->moduleid   = $data->id;
 | 
        
           |  |  | 1449 |   | 
        
           |  |  | 1450 |     $ratingoptions->userid = $userid;
 | 
        
           |  |  | 1451 |     $ratingoptions->aggregationmethod = $data->assessed;
 | 
        
           |  |  | 1452 |     $ratingoptions->scaleid = $data->scale;
 | 
        
           |  |  | 1453 |     $ratingoptions->itemtable = 'data_records';
 | 
        
           |  |  | 1454 |     $ratingoptions->itemtableusercolumn = 'userid';
 | 
        
           |  |  | 1455 |   | 
        
           |  |  | 1456 |     $rm = new rating_manager();
 | 
        
           |  |  | 1457 |     return $rm->get_user_grades($ratingoptions);
 | 
        
           |  |  | 1458 | }
 | 
        
           |  |  | 1459 |   | 
        
           |  |  | 1460 | /**
 | 
        
           |  |  | 1461 |  * Update activity grades
 | 
        
           |  |  | 1462 |  *
 | 
        
           |  |  | 1463 |  * @category grade
 | 
        
           |  |  | 1464 |  * @param object $data
 | 
        
           |  |  | 1465 |  * @param int $userid specific user only, 0 means all
 | 
        
           |  |  | 1466 |  * @param bool $nullifnone
 | 
        
           |  |  | 1467 |  */
 | 
        
           |  |  | 1468 | function data_update_grades($data, $userid=0, $nullifnone=true) {
 | 
        
           |  |  | 1469 |     global $CFG, $DB;
 | 
        
           |  |  | 1470 |     require_once($CFG->libdir.'/gradelib.php');
 | 
        
           |  |  | 1471 |   | 
        
           |  |  | 1472 |     if (!$data->assessed) {
 | 
        
           |  |  | 1473 |         data_grade_item_update($data);
 | 
        
           |  |  | 1474 |   | 
        
           |  |  | 1475 |     } else if ($grades = data_get_user_grades($data, $userid)) {
 | 
        
           |  |  | 1476 |         data_grade_item_update($data, $grades);
 | 
        
           |  |  | 1477 |   | 
        
           |  |  | 1478 |     } else if ($userid and $nullifnone) {
 | 
        
           |  |  | 1479 |         $grade = new stdClass();
 | 
        
           |  |  | 1480 |         $grade->userid   = $userid;
 | 
        
           |  |  | 1481 |         $grade->rawgrade = NULL;
 | 
        
           |  |  | 1482 |         data_grade_item_update($data, $grade);
 | 
        
           |  |  | 1483 |   | 
        
           |  |  | 1484 |     } else {
 | 
        
           |  |  | 1485 |         data_grade_item_update($data);
 | 
        
           |  |  | 1486 |     }
 | 
        
           |  |  | 1487 | }
 | 
        
           |  |  | 1488 |   | 
        
           |  |  | 1489 | /**
 | 
        
           |  |  | 1490 |  * Update/create grade item for given data
 | 
        
           |  |  | 1491 |  *
 | 
        
           |  |  | 1492 |  * @category grade
 | 
        
           |  |  | 1493 |  * @param stdClass $data A database instance with extra cmidnumber property
 | 
        
           |  |  | 1494 |  * @param mixed $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
 | 
        
           |  |  | 1495 |  * @return object grade_item
 | 
        
           |  |  | 1496 |  */
 | 
        
           |  |  | 1497 | function data_grade_item_update($data, $grades=NULL) {
 | 
        
           |  |  | 1498 |     global $CFG;
 | 
        
           |  |  | 1499 |     require_once($CFG->libdir.'/gradelib.php');
 | 
        
           |  |  | 1500 |   | 
        
           |  |  | 1501 |     $params = array('itemname'=>$data->name, 'idnumber'=>$data->cmidnumber);
 | 
        
           |  |  | 1502 |   | 
        
           |  |  | 1503 |     if (!$data->assessed or $data->scale == 0) {
 | 
        
           |  |  | 1504 |         $params['gradetype'] = GRADE_TYPE_NONE;
 | 
        
           |  |  | 1505 |   | 
        
           |  |  | 1506 |     } else if ($data->scale > 0) {
 | 
        
           |  |  | 1507 |         $params['gradetype'] = GRADE_TYPE_VALUE;
 | 
        
           |  |  | 1508 |         $params['grademax']  = $data->scale;
 | 
        
           |  |  | 1509 |         $params['grademin']  = 0;
 | 
        
           |  |  | 1510 |   | 
        
           |  |  | 1511 |     } else if ($data->scale < 0) {
 | 
        
           |  |  | 1512 |         $params['gradetype'] = GRADE_TYPE_SCALE;
 | 
        
           |  |  | 1513 |         $params['scaleid']   = -$data->scale;
 | 
        
           |  |  | 1514 |     }
 | 
        
           |  |  | 1515 |   | 
        
           |  |  | 1516 |     if ($grades  === 'reset') {
 | 
        
           |  |  | 1517 |         $params['reset'] = true;
 | 
        
           |  |  | 1518 |         $grades = NULL;
 | 
        
           |  |  | 1519 |     }
 | 
        
           |  |  | 1520 |   | 
        
           |  |  | 1521 |     return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grades, $params);
 | 
        
           |  |  | 1522 | }
 | 
        
           |  |  | 1523 |   | 
        
           |  |  | 1524 | /**
 | 
        
           |  |  | 1525 |  * Delete grade item for given data
 | 
        
           |  |  | 1526 |  *
 | 
        
           |  |  | 1527 |  * @category grade
 | 
        
           |  |  | 1528 |  * @param object $data object
 | 
        
           |  |  | 1529 |  * @return object grade_item
 | 
        
           |  |  | 1530 |  */
 | 
        
           |  |  | 1531 | function data_grade_item_delete($data) {
 | 
        
           |  |  | 1532 |     global $CFG;
 | 
        
           |  |  | 1533 |     require_once($CFG->libdir.'/gradelib.php');
 | 
        
           |  |  | 1534 |   | 
        
           |  |  | 1535 |     return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, array('deleted'=>1));
 | 
        
           |  |  | 1536 | }
 | 
        
           |  |  | 1537 |   | 
        
           |  |  | 1538 | // junk functions
 | 
        
           |  |  | 1539 |   | 
        
           |  |  | 1540 | /**
 | 
        
           |  |  | 1541 |  * Return rating related permissions
 | 
        
           |  |  | 1542 |  *
 | 
        
           |  |  | 1543 |  * @param string $contextid the context id
 | 
        
           |  |  | 1544 |  * @param string $component the component to get rating permissions for
 | 
        
           |  |  | 1545 |  * @param string $ratingarea the rating area to get permissions for
 | 
        
           |  |  | 1546 |  * @return array an associative array of the user's rating permissions
 | 
        
           |  |  | 1547 |  */
 | 
        
           |  |  | 1548 | function data_rating_permissions($contextid, $component, $ratingarea) {
 | 
        
           |  |  | 1549 |     $context = context::instance_by_id($contextid, MUST_EXIST);
 | 
        
           |  |  | 1550 |     if ($component != 'mod_data' || $ratingarea != 'entry') {
 | 
        
           |  |  | 1551 |         return null;
 | 
        
           |  |  | 1552 |     }
 | 
        
           |  |  | 1553 |     return array(
 | 
        
           |  |  | 1554 |         'view'    => has_capability('mod/data:viewrating',$context),
 | 
        
           |  |  | 1555 |         'viewany' => has_capability('mod/data:viewanyrating',$context),
 | 
        
           |  |  | 1556 |         'viewall' => has_capability('mod/data:viewallratings',$context),
 | 
        
           |  |  | 1557 |         'rate'    => has_capability('mod/data:rate',$context)
 | 
        
           |  |  | 1558 |     );
 | 
        
           |  |  | 1559 | }
 | 
        
           |  |  | 1560 |   | 
        
           |  |  | 1561 | /**
 | 
        
           |  |  | 1562 |  * Validates a submitted rating
 | 
        
           |  |  | 1563 |  * @param array $params submitted data
 | 
        
           |  |  | 1564 |  *            context => object the context in which the rated items exists [required]
 | 
        
           |  |  | 1565 |  *            itemid => int the ID of the object being rated
 | 
        
           |  |  | 1566 |  *            scaleid => int the scale from which the user can select a rating. Used for bounds checking. [required]
 | 
        
           |  |  | 1567 |  *            rating => int the submitted rating
 | 
        
           |  |  | 1568 |  *            rateduserid => int the id of the user whose items have been rated. NOT the user who submitted the ratings. 0 to update all. [required]
 | 
        
           |  |  | 1569 |  *            aggregation => int the aggregation method to apply when calculating grades ie RATING_AGGREGATE_AVERAGE [required]
 | 
        
           |  |  | 1570 |  * @return boolean true if the rating is valid. Will throw rating_exception if not
 | 
        
           |  |  | 1571 |  */
 | 
        
           |  |  | 1572 | function data_rating_validate($params) {
 | 
        
           |  |  | 1573 |     global $DB, $USER;
 | 
        
           |  |  | 1574 |   | 
        
           |  |  | 1575 |     // Check the component is mod_data
 | 
        
           |  |  | 1576 |     if ($params['component'] != 'mod_data') {
 | 
        
           |  |  | 1577 |         throw new rating_exception('invalidcomponent');
 | 
        
           |  |  | 1578 |     }
 | 
        
           |  |  | 1579 |   | 
        
           |  |  | 1580 |     // Check the ratingarea is entry (the only rating area in data module)
 | 
        
           |  |  | 1581 |     if ($params['ratingarea'] != 'entry') {
 | 
        
           |  |  | 1582 |         throw new rating_exception('invalidratingarea');
 | 
        
           |  |  | 1583 |     }
 | 
        
           |  |  | 1584 |   | 
        
           |  |  | 1585 |     // Check the rateduserid is not the current user .. you can't rate your own entries
 | 
        
           |  |  | 1586 |     if ($params['rateduserid'] == $USER->id) {
 | 
        
           |  |  | 1587 |         throw new rating_exception('nopermissiontorate');
 | 
        
           |  |  | 1588 |     }
 | 
        
           |  |  | 1589 |   | 
        
           |  |  | 1590 |     $datasql = "SELECT d.id as dataid, d.scale, d.course, r.userid as userid, d.approval, r.approved, r.timecreated, d.assesstimestart, d.assesstimefinish, r.groupid
 | 
        
           |  |  | 1591 |                   FROM {data_records} r
 | 
        
           |  |  | 1592 |                   JOIN {data} d ON r.dataid = d.id
 | 
        
           |  |  | 1593 |                  WHERE r.id = :itemid";
 | 
        
           |  |  | 1594 |     $dataparams = array('itemid'=>$params['itemid']);
 | 
        
           |  |  | 1595 |     if (!$info = $DB->get_record_sql($datasql, $dataparams)) {
 | 
        
           |  |  | 1596 |         //item doesn't exist
 | 
        
           |  |  | 1597 |         throw new rating_exception('invaliditemid');
 | 
        
           |  |  | 1598 |     }
 | 
        
           |  |  | 1599 |   | 
        
           |  |  | 1600 |     if ($info->scale != $params['scaleid']) {
 | 
        
           |  |  | 1601 |         //the scale being submitted doesnt match the one in the database
 | 
        
           |  |  | 1602 |         throw new rating_exception('invalidscaleid');
 | 
        
           |  |  | 1603 |     }
 | 
        
           |  |  | 1604 |   | 
        
           |  |  | 1605 |     //check that the submitted rating is valid for the scale
 | 
        
           |  |  | 1606 |   | 
        
           |  |  | 1607 |     // lower limit
 | 
        
           |  |  | 1608 |     if ($params['rating'] < 0  && $params['rating'] != RATING_UNSET_RATING) {
 | 
        
           |  |  | 1609 |         throw new rating_exception('invalidnum');
 | 
        
           |  |  | 1610 |     }
 | 
        
           |  |  | 1611 |   | 
        
           |  |  | 1612 |     // upper limit
 | 
        
           |  |  | 1613 |     if ($info->scale < 0) {
 | 
        
           |  |  | 1614 |         //its a custom scale
 | 
        
           |  |  | 1615 |         $scalerecord = $DB->get_record('scale', array('id' => -$info->scale));
 | 
        
           |  |  | 1616 |         if ($scalerecord) {
 | 
        
           |  |  | 1617 |             $scalearray = explode(',', $scalerecord->scale);
 | 
        
           |  |  | 1618 |             if ($params['rating'] > count($scalearray)) {
 | 
        
           |  |  | 1619 |                 throw new rating_exception('invalidnum');
 | 
        
           |  |  | 1620 |             }
 | 
        
           |  |  | 1621 |         } else {
 | 
        
           |  |  | 1622 |             throw new rating_exception('invalidscaleid');
 | 
        
           |  |  | 1623 |         }
 | 
        
           |  |  | 1624 |     } else if ($params['rating'] > $info->scale) {
 | 
        
           |  |  | 1625 |         //if its numeric and submitted rating is above maximum
 | 
        
           |  |  | 1626 |         throw new rating_exception('invalidnum');
 | 
        
           |  |  | 1627 |     }
 | 
        
           |  |  | 1628 |   | 
        
           |  |  | 1629 |     if ($info->approval && !$info->approved) {
 | 
        
           |  |  | 1630 |         //database requires approval but this item isnt approved
 | 
        
           |  |  | 1631 |         throw new rating_exception('nopermissiontorate');
 | 
        
           |  |  | 1632 |     }
 | 
        
           |  |  | 1633 |   | 
        
           |  |  | 1634 |     // check the item we're rating was created in the assessable time window
 | 
        
           |  |  | 1635 |     if (!empty($info->assesstimestart) && !empty($info->assesstimefinish)) {
 | 
        
           |  |  | 1636 |         if ($info->timecreated < $info->assesstimestart || $info->timecreated > $info->assesstimefinish) {
 | 
        
           |  |  | 1637 |             throw new rating_exception('notavailable');
 | 
        
           |  |  | 1638 |         }
 | 
        
           |  |  | 1639 |     }
 | 
        
           |  |  | 1640 |   | 
        
           |  |  | 1641 |     $course = $DB->get_record('course', array('id'=>$info->course), '*', MUST_EXIST);
 | 
        
           |  |  | 1642 |     $cm = get_coursemodule_from_instance('data', $info->dataid, $course->id, false, MUST_EXIST);
 | 
        
           |  |  | 1643 |     $context = context_module::instance($cm->id);
 | 
        
           |  |  | 1644 |   | 
        
           |  |  | 1645 |     // if the supplied context doesnt match the item's context
 | 
        
           |  |  | 1646 |     if ($context->id != $params['context']->id) {
 | 
        
           |  |  | 1647 |         throw new rating_exception('invalidcontext');
 | 
        
           |  |  | 1648 |     }
 | 
        
           |  |  | 1649 |   | 
        
           |  |  | 1650 |     // Make sure groups allow this user to see the item they're rating
 | 
        
           |  |  | 1651 |     $groupid = $info->groupid;
 | 
        
           |  |  | 1652 |     if ($groupid > 0 and $groupmode = groups_get_activity_groupmode($cm, $course)) {   // Groups are being used
 | 
        
           |  |  | 1653 |         if (!groups_group_exists($groupid)) { // Can't find group
 | 
        
           |  |  | 1654 |             throw new rating_exception('cannotfindgroup');//something is wrong
 | 
        
           |  |  | 1655 |         }
 | 
        
           |  |  | 1656 |   | 
        
           |  |  | 1657 |         if (!groups_is_member($groupid) and !has_capability('moodle/site:accessallgroups', $context)) {
 | 
        
           |  |  | 1658 |             // do not allow rating of posts from other groups when in SEPARATEGROUPS or VISIBLEGROUPS
 | 
        
           |  |  | 1659 |             throw new rating_exception('notmemberofgroup');
 | 
        
           |  |  | 1660 |         }
 | 
        
           |  |  | 1661 |     }
 | 
        
           |  |  | 1662 |   | 
        
           |  |  | 1663 |     return true;
 | 
        
           |  |  | 1664 | }
 | 
        
           |  |  | 1665 |   | 
        
           |  |  | 1666 | /**
 | 
        
           |  |  | 1667 |  * Can the current user see ratings for a given itemid?
 | 
        
           |  |  | 1668 |  *
 | 
        
           |  |  | 1669 |  * @param array $params submitted data
 | 
        
           |  |  | 1670 |  *            contextid => int contextid [required]
 | 
        
           |  |  | 1671 |  *            component => The component for this module - should always be mod_data [required]
 | 
        
           |  |  | 1672 |  *            ratingarea => object the context in which the rated items exists [required]
 | 
        
           |  |  | 1673 |  *            itemid => int the ID of the object being rated [required]
 | 
        
           |  |  | 1674 |  *            scaleid => int scale id [optional]
 | 
        
           |  |  | 1675 |  * @return bool
 | 
        
           |  |  | 1676 |  * @throws coding_exception
 | 
        
           |  |  | 1677 |  * @throws rating_exception
 | 
        
           |  |  | 1678 |  */
 | 
        
           |  |  | 1679 | function mod_data_rating_can_see_item_ratings($params) {
 | 
        
           |  |  | 1680 |     global $DB;
 | 
        
           |  |  | 1681 |   | 
        
           |  |  | 1682 |     // Check the component is mod_data.
 | 
        
           |  |  | 1683 |     if (!isset($params['component']) || $params['component'] != 'mod_data') {
 | 
        
           |  |  | 1684 |         throw new rating_exception('invalidcomponent');
 | 
        
           |  |  | 1685 |     }
 | 
        
           |  |  | 1686 |   | 
        
           |  |  | 1687 |     // Check the ratingarea is entry (the only rating area in data).
 | 
        
           |  |  | 1688 |     if (!isset($params['ratingarea']) || $params['ratingarea'] != 'entry') {
 | 
        
           |  |  | 1689 |         throw new rating_exception('invalidratingarea');
 | 
        
           |  |  | 1690 |     }
 | 
        
           |  |  | 1691 |   | 
        
           |  |  | 1692 |     if (!isset($params['itemid'])) {
 | 
        
           |  |  | 1693 |         throw new rating_exception('invaliditemid');
 | 
        
           |  |  | 1694 |     }
 | 
        
           |  |  | 1695 |   | 
        
           |  |  | 1696 |     $datasql = "SELECT d.id as dataid, d.course, r.groupid
 | 
        
           |  |  | 1697 |                   FROM {data_records} r
 | 
        
           |  |  | 1698 |                   JOIN {data} d ON r.dataid = d.id
 | 
        
           |  |  | 1699 |                  WHERE r.id = :itemid";
 | 
        
           |  |  | 1700 |     $dataparams = array('itemid' => $params['itemid']);
 | 
        
           |  |  | 1701 |     if (!$info = $DB->get_record_sql($datasql, $dataparams)) {
 | 
        
           |  |  | 1702 |         // Item doesn't exist.
 | 
        
           |  |  | 1703 |         throw new rating_exception('invaliditemid');
 | 
        
           |  |  | 1704 |     }
 | 
        
           |  |  | 1705 |   | 
        
           |  |  | 1706 |     // User can see ratings of all participants.
 | 
        
           |  |  | 1707 |     if ($info->groupid == 0) {
 | 
        
           |  |  | 1708 |         return true;
 | 
        
           |  |  | 1709 |     }
 | 
        
           |  |  | 1710 |   | 
        
           |  |  | 1711 |     $course = $DB->get_record('course', array('id' => $info->course), '*', MUST_EXIST);
 | 
        
           |  |  | 1712 |     $cm = get_coursemodule_from_instance('data', $info->dataid, $course->id, false, MUST_EXIST);
 | 
        
           |  |  | 1713 |   | 
        
           |  |  | 1714 |     // Make sure groups allow this user to see the item they're rating.
 | 
        
           |  |  | 1715 |     return groups_group_visible($info->groupid, $course, $cm);
 | 
        
           |  |  | 1716 | }
 | 
        
           |  |  | 1717 |   | 
        
           |  |  | 1718 |   | 
        
           |  |  | 1719 | /**
 | 
        
           |  |  | 1720 |  * function that takes in the current data, number of items per page,
 | 
        
           |  |  | 1721 |  * a search string and prints a preference box in view.php
 | 
        
           |  |  | 1722 |  *
 | 
        
           |  |  | 1723 |  * This preference box prints a searchable advanced search template if
 | 
        
           |  |  | 1724 |  *     a) A template is defined
 | 
        
           |  |  | 1725 |  *  b) The advanced search checkbox is checked.
 | 
        
           |  |  | 1726 |  *
 | 
        
           |  |  | 1727 |  * @global object
 | 
        
           |  |  | 1728 |  * @global object
 | 
        
           |  |  | 1729 |  * @param object $data
 | 
        
           |  |  | 1730 |  * @param int $perpage
 | 
        
           |  |  | 1731 |  * @param string $search
 | 
        
           |  |  | 1732 |  * @param string $sort
 | 
        
           |  |  | 1733 |  * @param string $order
 | 
        
           |  |  | 1734 |  * @param array $search_array
 | 
        
           |  |  | 1735 |  * @param int $advanced
 | 
        
           |  |  | 1736 |  * @param string $mode
 | 
        
           |  |  | 1737 |  * @return void
 | 
        
           |  |  | 1738 |  */
 | 
        
           |  |  | 1739 | function data_print_preference_form($data, $perpage, $search, $sort='', $order='ASC', $search_array = '', $advanced = 0, $mode= ''){
 | 
        
           |  |  | 1740 |     global $DB, $PAGE, $OUTPUT;
 | 
        
           |  |  | 1741 |   | 
        
           |  |  | 1742 |     $cm = get_coursemodule_from_instance('data', $data->id);
 | 
        
           |  |  | 1743 |     $context = context_module::instance($cm->id);
 | 
        
           |  |  | 1744 |     echo '<div class="datapreferences my-5">';
 | 
        
           |  |  | 1745 |     echo '<form id="options" action="view.php" method="get">';
 | 
        
           | 1441 | ariadna | 1746 |     echo '<div class="d-flex flex-wrap align-items-center gap-1">';
 | 
        
           | 1 | efrain | 1747 |     echo '<input type="hidden" name="d" value="'.$data->id.'" />';
 | 
        
           |  |  | 1748 |     if ($mode =='asearch') {
 | 
        
           |  |  | 1749 |         $advanced = 1;
 | 
        
           |  |  | 1750 |         echo '<input type="hidden" name="mode" value="list" />';
 | 
        
           |  |  | 1751 |     }
 | 
        
           |  |  | 1752 |     echo '<label for="pref_perpage">'.get_string('pagesize','data').'</label> ';
 | 
        
           |  |  | 1753 |     $pagesizes = array(2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,10=>10,15=>15,
 | 
        
           |  |  | 1754 |                        20=>20,30=>30,40=>40,50=>50,100=>100,200=>200,300=>300,400=>400,500=>500,1000=>1000);
 | 
        
           |  |  | 1755 |     echo html_writer::select($pagesizes, 'perpage', $perpage, false, array('id' => 'pref_perpage',
 | 
        
           | 1441 | ariadna | 1756 |         'class' => 'form-select me-1'));
 | 
        
           | 1 | efrain | 1757 |   | 
        
           |  |  | 1758 |     if ($advanced) {
 | 
        
           |  |  | 1759 |         $regsearchclass = 'search_none';
 | 
        
           |  |  | 1760 |         $advancedsearchclass = 'search_inline';
 | 
        
           |  |  | 1761 |     } else {
 | 
        
           |  |  | 1762 |         $regsearchclass = 'search_inline';
 | 
        
           |  |  | 1763 |         $advancedsearchclass = 'search_none';
 | 
        
           |  |  | 1764 |     }
 | 
        
           | 1441 | ariadna | 1765 |     echo '<div id="reg_search" class="' . $regsearchclass . ' me-1" >';
 | 
        
           |  |  | 1766 |     echo '<label for="pref_search" class="me-1">' . get_string('search') . '</label><input type="text" ' .
 | 
        
           |  |  | 1767 |          'class="form-control d-inline-block align-middle w-auto me-1" size="16" name="search" id= "pref_search" value="' . s($search) . '" /></div>';
 | 
        
           | 1 | efrain | 1768 |     echo '<label for="pref_sortby">'.get_string('sortby').'</label> ';
 | 
        
           |  |  | 1769 |     // foreach field, print the option
 | 
        
           | 1441 | ariadna | 1770 |     echo '<select name="sort" id="pref_sortby" class="form-select me-1">';
 | 
        
           | 1 | efrain | 1771 |     if ($fields = $DB->get_records('data_fields', array('dataid'=>$data->id), 'name')) {
 | 
        
           |  |  | 1772 |         echo '<optgroup label="'.get_string('fields', 'data').'">';
 | 
        
           |  |  | 1773 |         foreach ($fields as $field) {
 | 
        
           |  |  | 1774 |             if ($field->id == $sort) {
 | 
        
           |  |  | 1775 |                 echo '<option value="'.$field->id.'" selected="selected">'.s($field->name).'</option>';
 | 
        
           |  |  | 1776 |             } else {
 | 
        
           |  |  | 1777 |                 echo '<option value="'.$field->id.'">'.s($field->name).'</option>';
 | 
        
           |  |  | 1778 |             }
 | 
        
           |  |  | 1779 |         }
 | 
        
           |  |  | 1780 |         echo '</optgroup>';
 | 
        
           |  |  | 1781 |     }
 | 
        
           |  |  | 1782 |     $options = array();
 | 
        
           |  |  | 1783 |     $options[DATA_TIMEADDED]    = get_string('timeadded', 'data');
 | 
        
           |  |  | 1784 |     $options[DATA_TIMEMODIFIED] = get_string('timemodified', 'data');
 | 
        
           |  |  | 1785 |     $options[DATA_FIRSTNAME]    = get_string('authorfirstname', 'data');
 | 
        
           |  |  | 1786 |     $options[DATA_LASTNAME]     = get_string('authorlastname', 'data');
 | 
        
           |  |  | 1787 |     if ($data->approval and has_capability('mod/data:approve', $context)) {
 | 
        
           |  |  | 1788 |         $options[DATA_APPROVED] = get_string('approved', 'data');
 | 
        
           |  |  | 1789 |     }
 | 
        
           |  |  | 1790 |     echo '<optgroup label="'.get_string('other', 'data').'">';
 | 
        
           |  |  | 1791 |     foreach ($options as $key => $name) {
 | 
        
           |  |  | 1792 |         if ($key == $sort) {
 | 
        
           |  |  | 1793 |             echo '<option value="'.$key.'" selected="selected">'.$name.'</option>';
 | 
        
           |  |  | 1794 |         } else {
 | 
        
           |  |  | 1795 |             echo '<option value="'.$key.'">'.$name.'</option>';
 | 
        
           |  |  | 1796 |         }
 | 
        
           |  |  | 1797 |     }
 | 
        
           |  |  | 1798 |     echo '</optgroup>';
 | 
        
           |  |  | 1799 |     echo '</select>';
 | 
        
           |  |  | 1800 |     echo '<label for="pref_order" class="accesshide">'.get_string('order').'</label>';
 | 
        
           | 1441 | ariadna | 1801 |     echo '<select id="pref_order" name="order" class="form-select me-1">';
 | 
        
           | 1 | efrain | 1802 |     if ($order == 'ASC') {
 | 
        
           |  |  | 1803 |         echo '<option value="ASC" selected="selected">'.get_string('ascending','data').'</option>';
 | 
        
           |  |  | 1804 |     } else {
 | 
        
           |  |  | 1805 |         echo '<option value="ASC">'.get_string('ascending','data').'</option>';
 | 
        
           |  |  | 1806 |     }
 | 
        
           |  |  | 1807 |     if ($order == 'DESC') {
 | 
        
           |  |  | 1808 |         echo '<option value="DESC" selected="selected">'.get_string('descending','data').'</option>';
 | 
        
           |  |  | 1809 |     } else {
 | 
        
           |  |  | 1810 |         echo '<option value="DESC">'.get_string('descending','data').'</option>';
 | 
        
           |  |  | 1811 |     }
 | 
        
           |  |  | 1812 |     echo '</select>';
 | 
        
           |  |  | 1813 |   | 
        
           |  |  | 1814 |     if ($advanced) {
 | 
        
           |  |  | 1815 |         $checked = ' checked="checked" ';
 | 
        
           |  |  | 1816 |     }
 | 
        
           |  |  | 1817 |     else {
 | 
        
           |  |  | 1818 |         $checked = '';
 | 
        
           |  |  | 1819 |     }
 | 
        
           |  |  | 1820 |     $PAGE->requires->js('/mod/data/data.js');
 | 
        
           |  |  | 1821 |     echo '<input type="hidden" name="advanced" value="0" />';
 | 
        
           |  |  | 1822 |     echo '<input type="hidden" name="filter" value="1" />';
 | 
        
           |  |  | 1823 |     echo '<input type="checkbox" id="advancedcheckbox" name="advanced" value="1" ' . $checked . ' ' .
 | 
        
           |  |  | 1824 |          'onchange="showHideAdvSearch(this.checked);" class="mx-1" />' .
 | 
        
           |  |  | 1825 |          '<label for="advancedcheckbox">' . get_string('advancedsearch', 'data') . '</label>';
 | 
        
           | 1441 | ariadna | 1826 |     echo '<div id="advsearch-save-sec" class="ms-3 '. $regsearchclass . '">';
 | 
        
           | 1 | efrain | 1827 |     echo '<input type="submit" class="btn btn-secondary" value="' . get_string('savesettings', 'data') . '" />';
 | 
        
           |  |  | 1828 |     echo '</div>';
 | 
        
           |  |  | 1829 |     echo '</div>';
 | 
        
           |  |  | 1830 |   | 
        
           |  |  | 1831 |     echo '<br />';
 | 
        
           |  |  | 1832 |     echo '<div class="' . $advancedsearchclass . '" id="data_adv_form">';
 | 
        
           |  |  | 1833 |     echo '<table class="boxaligncenter">';
 | 
        
           |  |  | 1834 |   | 
        
           |  |  | 1835 |     // print ASC or DESC
 | 
        
           |  |  | 1836 |     echo '<tr><td colspan="2"> </td></tr>';
 | 
        
           |  |  | 1837 |     $i = 0;
 | 
        
           |  |  | 1838 |   | 
        
           |  |  | 1839 |     // Determine if we are printing all fields for advanced search, or the template for advanced search
 | 
        
           |  |  | 1840 |     // If a template is not defined, use the deafault template and display all fields.
 | 
        
           |  |  | 1841 |     $asearchtemplate = $data->asearchtemplate;
 | 
        
           |  |  | 1842 |     if (empty($asearchtemplate)) {
 | 
        
           |  |  | 1843 |         $asearchtemplate = data_generate_default_template($data, 'asearchtemplate', 0, false, false);
 | 
        
           |  |  | 1844 |     }
 | 
        
           |  |  | 1845 |   | 
        
           |  |  | 1846 |     static $fields = array();
 | 
        
           |  |  | 1847 |     static $dataid = null;
 | 
        
           |  |  | 1848 |   | 
        
           |  |  | 1849 |     if (empty($dataid)) {
 | 
        
           |  |  | 1850 |         $dataid = $data->id;
 | 
        
           |  |  | 1851 |     } else if ($dataid != $data->id) {
 | 
        
           |  |  | 1852 |         $fields = array();
 | 
        
           |  |  | 1853 |     }
 | 
        
           |  |  | 1854 |   | 
        
           |  |  | 1855 |     if (empty($fields)) {
 | 
        
           |  |  | 1856 |         $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$data->id));
 | 
        
           |  |  | 1857 |         foreach ($fieldrecords as $fieldrecord) {
 | 
        
           |  |  | 1858 |             $fields[]= data_get_field($fieldrecord, $data);
 | 
        
           |  |  | 1859 |         }
 | 
        
           |  |  | 1860 |     }
 | 
        
           |  |  | 1861 |   | 
        
           |  |  | 1862 |     // Replacing tags
 | 
        
           |  |  | 1863 |     $patterns = array();
 | 
        
           |  |  | 1864 |     $replacement = array();
 | 
        
           |  |  | 1865 |   | 
        
           |  |  | 1866 |     // Then we generate strings to replace for normal tags
 | 
        
           |  |  | 1867 |     $otherfields = [];
 | 
        
           |  |  | 1868 |     foreach ($fields as $field) {
 | 
        
           |  |  | 1869 |         $fieldname = $field->field->name;
 | 
        
           |  |  | 1870 |         $fieldname = preg_quote($fieldname, '/');
 | 
        
           |  |  | 1871 |         $searchfield = data_get_field_from_id($field->field->id, $data);
 | 
        
           |  |  | 1872 |   | 
        
           |  |  | 1873 |         if ($searchfield->type === 'unknown') {
 | 
        
           |  |  | 1874 |             continue;
 | 
        
           |  |  | 1875 |         }
 | 
        
           |  |  | 1876 |         if (!empty($search_array[$field->field->id]->data)) {
 | 
        
           |  |  | 1877 |             $searchinput = $searchfield->display_search_field($search_array[$field->field->id]->data);
 | 
        
           |  |  | 1878 |         } else {
 | 
        
           |  |  | 1879 |             $searchinput = $searchfield->display_search_field();
 | 
        
           |  |  | 1880 |         }
 | 
        
           |  |  | 1881 |         $patterns[] = "/\[\[$fieldname\]\]/i";
 | 
        
           |  |  | 1882 |         $replacement[] = $searchinput;
 | 
        
           |  |  | 1883 |         // Extra field information.
 | 
        
           |  |  | 1884 |         $patterns[] = "/\[\[$fieldname#name\]\]/i";
 | 
        
           |  |  | 1885 |         $replacement[] = $field->field->name;
 | 
        
           |  |  | 1886 |         $patterns[] = "/\[\[$fieldname#description\]\]/i";
 | 
        
           |  |  | 1887 |         $replacement[] = $field->field->description;
 | 
        
           |  |  | 1888 |         // Other fields.
 | 
        
           |  |  | 1889 |         if (strpos($asearchtemplate, "[[" . $field->field->name . "]]") === false) {
 | 
        
           |  |  | 1890 |             $otherfields[] = [
 | 
        
           |  |  | 1891 |                 'fieldname' => $searchfield->field->name,
 | 
        
           |  |  | 1892 |                 'fieldcontent' => $searchinput,
 | 
        
           |  |  | 1893 |             ];
 | 
        
           |  |  | 1894 |         }
 | 
        
           |  |  | 1895 |     }
 | 
        
           |  |  | 1896 |     $patterns[] = "/##otherfields##/";
 | 
        
           |  |  | 1897 |     if (!empty($otherfields)) {
 | 
        
           |  |  | 1898 |         $replacement[] = $OUTPUT->render_from_template(
 | 
        
           |  |  | 1899 |             'mod_data/fields_otherfields',
 | 
        
           |  |  | 1900 |             ['fields' => $otherfields]
 | 
        
           |  |  | 1901 |         );
 | 
        
           |  |  | 1902 |     } else {
 | 
        
           |  |  | 1903 |         $replacement[] = '';
 | 
        
           |  |  | 1904 |     }
 | 
        
           |  |  | 1905 |   | 
        
           |  |  | 1906 |     $fn = !empty($search_array[DATA_FIRSTNAME]->data) ? $search_array[DATA_FIRSTNAME]->data : '';
 | 
        
           |  |  | 1907 |     $ln = !empty($search_array[DATA_LASTNAME]->data) ? $search_array[DATA_LASTNAME]->data : '';
 | 
        
           |  |  | 1908 |     $patterns[]    = '/##firstname##/';
 | 
        
           |  |  | 1909 |     $replacement[] = '<label class="accesshide" for="u_fn">' . get_string('authorfirstname', 'data') . '</label>' .
 | 
        
           |  |  | 1910 |                      '<input type="text" class="form-control" size="16" id="u_fn" name="u_fn" value="' . s($fn) . '" />';
 | 
        
           |  |  | 1911 |     $patterns[]    = '/##lastname##/';
 | 
        
           |  |  | 1912 |     $replacement[] = '<label class="accesshide" for="u_ln">' . get_string('authorlastname', 'data') . '</label>' .
 | 
        
           |  |  | 1913 |                      '<input type="text" class="form-control" size="16" id="u_ln" name="u_ln" value="' . s($ln) . '" />';
 | 
        
           |  |  | 1914 |   | 
        
           |  |  | 1915 |     if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
 | 
        
           |  |  | 1916 |         $patterns[] = "/##tags##/";
 | 
        
           |  |  | 1917 |         $selectedtags = isset($search_array[DATA_TAGS]->rawtagnames) ? $search_array[DATA_TAGS]->rawtagnames : [];
 | 
        
           |  |  | 1918 |         $replacement[] = data_generate_tag_form(false, $selectedtags);
 | 
        
           |  |  | 1919 |     }
 | 
        
           |  |  | 1920 |   | 
        
           |  |  | 1921 |     // actual replacement of the tags
 | 
        
           |  |  | 1922 |   | 
        
           |  |  | 1923 |     $options = new stdClass();
 | 
        
           |  |  | 1924 |     $options->para=false;
 | 
        
           |  |  | 1925 |     $options->noclean=true;
 | 
        
           |  |  | 1926 |     echo '<tr><td>';
 | 
        
           |  |  | 1927 |     echo preg_replace($patterns, $replacement, format_text($asearchtemplate, FORMAT_HTML, $options));
 | 
        
           |  |  | 1928 |     echo '</td></tr>';
 | 
        
           |  |  | 1929 |   | 
        
           |  |  | 1930 |     echo '<tr><td colspan="4"><br/>' .
 | 
        
           | 1441 | ariadna | 1931 |          '<input type="submit" class="btn btn-primary me-1" value="' . get_string('savesettings', 'data') . '" />' .
 | 
        
           | 1 | efrain | 1932 |          '<input type="submit" class="btn btn-secondary" name="resetadv" value="' . get_string('resetsettings', 'data') . '" />' .
 | 
        
           |  |  | 1933 |          '</td></tr>';
 | 
        
           |  |  | 1934 |     echo '</table>';
 | 
        
           |  |  | 1935 |     echo '</div>';
 | 
        
           |  |  | 1936 |     echo '</form>';
 | 
        
           |  |  | 1937 |     echo '</div>';
 | 
        
           |  |  | 1938 |     echo '<hr/>';
 | 
        
           |  |  | 1939 | }
 | 
        
           |  |  | 1940 |   | 
        
           |  |  | 1941 | /**
 | 
        
           |  |  | 1942 |  * @global object
 | 
        
           |  |  | 1943 |  * @global object
 | 
        
           |  |  | 1944 |  * @param object $data
 | 
        
           |  |  | 1945 |  * @param object $record
 | 
        
           |  |  | 1946 |  * @param bool $print if the result must be printed or returner.
 | 
        
           |  |  | 1947 |  * @return void Output echo'd
 | 
        
           |  |  | 1948 |  */
 | 
        
           |  |  | 1949 | function data_print_ratings($data, $record, bool $print = true) {
 | 
        
           |  |  | 1950 |     global $OUTPUT;
 | 
        
           |  |  | 1951 |     $result = '';
 | 
        
           |  |  | 1952 |     if (!empty($record->rating)){
 | 
        
           |  |  | 1953 |         $result = $OUTPUT->render($record->rating);
 | 
        
           |  |  | 1954 |     }
 | 
        
           |  |  | 1955 |     if (!$print) {
 | 
        
           |  |  | 1956 |         return $result;
 | 
        
           |  |  | 1957 |     }
 | 
        
           |  |  | 1958 |     echo $result;
 | 
        
           |  |  | 1959 | }
 | 
        
           |  |  | 1960 |   | 
        
           |  |  | 1961 | /**
 | 
        
           |  |  | 1962 |  * List the actions that correspond to a view of this module.
 | 
        
           |  |  | 1963 |  * This is used by the participation report.
 | 
        
           |  |  | 1964 |  *
 | 
        
           |  |  | 1965 |  * Note: This is not used by new logging system. Event with
 | 
        
           |  |  | 1966 |  *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
 | 
        
           |  |  | 1967 |  *       be considered as view action.
 | 
        
           |  |  | 1968 |  *
 | 
        
           |  |  | 1969 |  * @return array
 | 
        
           |  |  | 1970 |  */
 | 
        
           |  |  | 1971 | function data_get_view_actions() {
 | 
        
           |  |  | 1972 |     return array('view');
 | 
        
           |  |  | 1973 | }
 | 
        
           |  |  | 1974 |   | 
        
           |  |  | 1975 | /**
 | 
        
           |  |  | 1976 |  * List the actions that correspond to a post of this module.
 | 
        
           |  |  | 1977 |  * This is used by the participation report.
 | 
        
           |  |  | 1978 |  *
 | 
        
           |  |  | 1979 |  * Note: This is not used by new logging system. Event with
 | 
        
           |  |  | 1980 |  *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
 | 
        
           |  |  | 1981 |  *       will be considered as post action.
 | 
        
           |  |  | 1982 |  *
 | 
        
           |  |  | 1983 |  * @return array
 | 
        
           |  |  | 1984 |  */
 | 
        
           |  |  | 1985 | function data_get_post_actions() {
 | 
        
           |  |  | 1986 |     return array('add','update','record delete');
 | 
        
           |  |  | 1987 | }
 | 
        
           |  |  | 1988 |   | 
        
           |  |  | 1989 | /**
 | 
        
           |  |  | 1990 |  * @param string $name
 | 
        
           |  |  | 1991 |  * @param int $dataid
 | 
        
           |  |  | 1992 |  * @param int $fieldid
 | 
        
           |  |  | 1993 |  * @return bool
 | 
        
           |  |  | 1994 |  */
 | 
        
           |  |  | 1995 | function data_fieldname_exists($name, $dataid, $fieldid = 0) {
 | 
        
           |  |  | 1996 |     global $DB;
 | 
        
           |  |  | 1997 |   | 
        
           |  |  | 1998 |     if (!is_numeric($name)) {
 | 
        
           |  |  | 1999 |         $like = $DB->sql_like('df.name', ':name', false);
 | 
        
           |  |  | 2000 |     } else {
 | 
        
           |  |  | 2001 |         $like = "df.name = :name";
 | 
        
           |  |  | 2002 |     }
 | 
        
           |  |  | 2003 |     $params = array('name'=>$name);
 | 
        
           |  |  | 2004 |     if ($fieldid) {
 | 
        
           |  |  | 2005 |         $params['dataid']   = $dataid;
 | 
        
           |  |  | 2006 |         $params['fieldid1'] = $fieldid;
 | 
        
           |  |  | 2007 |         $params['fieldid2'] = $fieldid;
 | 
        
           |  |  | 2008 |         return $DB->record_exists_sql("SELECT * FROM {data_fields} df
 | 
        
           |  |  | 2009 |                                         WHERE $like AND df.dataid = :dataid
 | 
        
           |  |  | 2010 |                                               AND ((df.id < :fieldid1) OR (df.id > :fieldid2))", $params);
 | 
        
           |  |  | 2011 |     } else {
 | 
        
           |  |  | 2012 |         $params['dataid']   = $dataid;
 | 
        
           |  |  | 2013 |         return $DB->record_exists_sql("SELECT * FROM {data_fields} df
 | 
        
           |  |  | 2014 |                                         WHERE $like AND df.dataid = :dataid", $params);
 | 
        
           |  |  | 2015 |     }
 | 
        
           |  |  | 2016 | }
 | 
        
           |  |  | 2017 |   | 
        
           |  |  | 2018 | /**
 | 
        
           |  |  | 2019 |  * @param array $fieldinput
 | 
        
           |  |  | 2020 |  */
 | 
        
           |  |  | 2021 | function data_convert_arrays_to_strings(&$fieldinput) {
 | 
        
           |  |  | 2022 |     foreach ($fieldinput as $key => $val) {
 | 
        
           |  |  | 2023 |         if (is_array($val)) {
 | 
        
           |  |  | 2024 |             $str = '';
 | 
        
           |  |  | 2025 |             foreach ($val as $inner) {
 | 
        
           |  |  | 2026 |                 $str .= $inner . ',';
 | 
        
           |  |  | 2027 |             }
 | 
        
           |  |  | 2028 |             $str = substr($str, 0, -1);
 | 
        
           |  |  | 2029 |   | 
        
           |  |  | 2030 |             $fieldinput->$key = $str;
 | 
        
           |  |  | 2031 |         }
 | 
        
           |  |  | 2032 |     }
 | 
        
           |  |  | 2033 | }
 | 
        
           |  |  | 2034 |   | 
        
           |  |  | 2035 |   | 
        
           |  |  | 2036 | /**
 | 
        
           |  |  | 2037 |  * Converts a database (module instance) to use the Roles System
 | 
        
           |  |  | 2038 |  *
 | 
        
           |  |  | 2039 |  * @global object
 | 
        
           |  |  | 2040 |  * @global object
 | 
        
           |  |  | 2041 |  * @uses CONTEXT_MODULE
 | 
        
           |  |  | 2042 |  * @uses CAP_PREVENT
 | 
        
           |  |  | 2043 |  * @uses CAP_ALLOW
 | 
        
           |  |  | 2044 |  * @param object $data a data object with the same attributes as a record
 | 
        
           |  |  | 2045 |  *                     from the data database table
 | 
        
           |  |  | 2046 |  * @param int $datamodid the id of the data module, from the modules table
 | 
        
           |  |  | 2047 |  * @param array $teacherroles array of roles that have archetype teacher
 | 
        
           |  |  | 2048 |  * @param array $studentroles array of roles that have archetype student
 | 
        
           |  |  | 2049 |  * @param array $guestroles array of roles that have archetype guest
 | 
        
           |  |  | 2050 |  * @param int $cmid the course_module id for this data instance
 | 
        
           |  |  | 2051 |  * @return boolean data module was converted or not
 | 
        
           |  |  | 2052 |  */
 | 
        
           |  |  | 2053 | function data_convert_to_roles($data, $teacherroles=array(), $studentroles=array(), $cmid=NULL) {
 | 
        
           |  |  | 2054 |     global $CFG, $DB, $OUTPUT;
 | 
        
           |  |  | 2055 |   | 
        
           |  |  | 2056 |     if (!isset($data->participants) && !isset($data->assesspublic)
 | 
        
           |  |  | 2057 |             && !isset($data->groupmode)) {
 | 
        
           |  |  | 2058 |         // We assume that this database has already been converted to use the
 | 
        
           |  |  | 2059 |         // Roles System. above fields get dropped the data module has been
 | 
        
           |  |  | 2060 |         // upgraded to use Roles.
 | 
        
           |  |  | 2061 |         return false;
 | 
        
           |  |  | 2062 |     }
 | 
        
           |  |  | 2063 |   | 
        
           |  |  | 2064 |     if (empty($cmid)) {
 | 
        
           |  |  | 2065 |         // We were not given the course_module id. Try to find it.
 | 
        
           |  |  | 2066 |         if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
 | 
        
           |  |  | 2067 |             echo $OUTPUT->notification('Could not get the course module for the data');
 | 
        
           |  |  | 2068 |             return false;
 | 
        
           |  |  | 2069 |         } else {
 | 
        
           |  |  | 2070 |             $cmid = $cm->id;
 | 
        
           |  |  | 2071 |         }
 | 
        
           |  |  | 2072 |     }
 | 
        
           |  |  | 2073 |     $context = context_module::instance($cmid);
 | 
        
           |  |  | 2074 |   | 
        
           |  |  | 2075 |   | 
        
           |  |  | 2076 |     // $data->participants:
 | 
        
           |  |  | 2077 |     // 1 - Only teachers can add entries
 | 
        
           |  |  | 2078 |     // 3 - Teachers and students can add entries
 | 
        
           |  |  | 2079 |     switch ($data->participants) {
 | 
        
           |  |  | 2080 |         case 1:
 | 
        
           |  |  | 2081 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2082 |                 assign_capability('mod/data:writeentry', CAP_PREVENT, $studentrole->id, $context->id);
 | 
        
           |  |  | 2083 |             }
 | 
        
           |  |  | 2084 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2085 |                 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2086 |             }
 | 
        
           |  |  | 2087 |             break;
 | 
        
           |  |  | 2088 |         case 3:
 | 
        
           |  |  | 2089 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2090 |                 assign_capability('mod/data:writeentry', CAP_ALLOW, $studentrole->id, $context->id);
 | 
        
           |  |  | 2091 |             }
 | 
        
           |  |  | 2092 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2093 |                 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2094 |             }
 | 
        
           |  |  | 2095 |             break;
 | 
        
           |  |  | 2096 |     }
 | 
        
           |  |  | 2097 |   | 
        
           |  |  | 2098 |     // $data->assessed:
 | 
        
           |  |  | 2099 |     // 2 - Only teachers can rate posts
 | 
        
           |  |  | 2100 |     // 1 - Everyone can rate posts
 | 
        
           |  |  | 2101 |     // 0 - No one can rate posts
 | 
        
           |  |  | 2102 |     switch ($data->assessed) {
 | 
        
           |  |  | 2103 |         case 0:
 | 
        
           |  |  | 2104 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2105 |                 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
 | 
        
           |  |  | 2106 |             }
 | 
        
           |  |  | 2107 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2108 |                 assign_capability('mod/data:rate', CAP_PREVENT, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2109 |             }
 | 
        
           |  |  | 2110 |             break;
 | 
        
           |  |  | 2111 |         case 1:
 | 
        
           |  |  | 2112 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2113 |                 assign_capability('mod/data:rate', CAP_ALLOW, $studentrole->id, $context->id);
 | 
        
           |  |  | 2114 |             }
 | 
        
           |  |  | 2115 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2116 |                 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2117 |             }
 | 
        
           |  |  | 2118 |             break;
 | 
        
           |  |  | 2119 |         case 2:
 | 
        
           |  |  | 2120 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2121 |                 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
 | 
        
           |  |  | 2122 |             }
 | 
        
           |  |  | 2123 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2124 |                 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2125 |             }
 | 
        
           |  |  | 2126 |             break;
 | 
        
           |  |  | 2127 |     }
 | 
        
           |  |  | 2128 |   | 
        
           |  |  | 2129 |     // $data->assesspublic:
 | 
        
           |  |  | 2130 |     // 0 - Students can only see their own ratings
 | 
        
           |  |  | 2131 |     // 1 - Students can see everyone's ratings
 | 
        
           |  |  | 2132 |     switch ($data->assesspublic) {
 | 
        
           |  |  | 2133 |         case 0:
 | 
        
           |  |  | 2134 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2135 |                 assign_capability('mod/data:viewrating', CAP_PREVENT, $studentrole->id, $context->id);
 | 
        
           |  |  | 2136 |             }
 | 
        
           |  |  | 2137 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2138 |                 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2139 |             }
 | 
        
           |  |  | 2140 |             break;
 | 
        
           |  |  | 2141 |         case 1:
 | 
        
           |  |  | 2142 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2143 |                 assign_capability('mod/data:viewrating', CAP_ALLOW, $studentrole->id, $context->id);
 | 
        
           |  |  | 2144 |             }
 | 
        
           |  |  | 2145 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2146 |                 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2147 |             }
 | 
        
           |  |  | 2148 |             break;
 | 
        
           |  |  | 2149 |     }
 | 
        
           |  |  | 2150 |   | 
        
           |  |  | 2151 |     if (empty($cm)) {
 | 
        
           |  |  | 2152 |         $cm = $DB->get_record('course_modules', array('id'=>$cmid));
 | 
        
           |  |  | 2153 |     }
 | 
        
           |  |  | 2154 |   | 
        
           |  |  | 2155 |     switch ($cm->groupmode) {
 | 
        
           |  |  | 2156 |         case NOGROUPS:
 | 
        
           |  |  | 2157 |             break;
 | 
        
           |  |  | 2158 |         case SEPARATEGROUPS:
 | 
        
           |  |  | 2159 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2160 |                 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $studentrole->id, $context->id);
 | 
        
           |  |  | 2161 |             }
 | 
        
           |  |  | 2162 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2163 |                 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2164 |             }
 | 
        
           |  |  | 2165 |             break;
 | 
        
           |  |  | 2166 |         case VISIBLEGROUPS:
 | 
        
           |  |  | 2167 |             foreach ($studentroles as $studentrole) {
 | 
        
           |  |  | 2168 |                 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $studentrole->id, $context->id);
 | 
        
           |  |  | 2169 |             }
 | 
        
           |  |  | 2170 |             foreach ($teacherroles as $teacherrole) {
 | 
        
           |  |  | 2171 |                 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
 | 
        
           |  |  | 2172 |             }
 | 
        
           |  |  | 2173 |             break;
 | 
        
           |  |  | 2174 |     }
 | 
        
           |  |  | 2175 |     return true;
 | 
        
           |  |  | 2176 | }
 | 
        
           |  |  | 2177 |   | 
        
           |  |  | 2178 | /**
 | 
        
           |  |  | 2179 |  * Prints the heads for a page
 | 
        
           |  |  | 2180 |  *
 | 
        
           |  |  | 2181 |  * @param stdClass $course
 | 
        
           |  |  | 2182 |  * @param stdClass $cm
 | 
        
           |  |  | 2183 |  * @param stdClass $data
 | 
        
           |  |  | 2184 |  * @param string $currenttab
 | 
        
           |  |  | 2185 |  * @param string $actionbar
 | 
        
           |  |  | 2186 |  */
 | 
        
           |  |  | 2187 | function data_print_header($course, $cm, $data, $currenttab='', string $actionbar = '') {
 | 
        
           |  |  | 2188 |   | 
        
           |  |  | 2189 |     global $CFG, $displaynoticegood, $displaynoticebad, $OUTPUT, $PAGE, $USER;
 | 
        
           |  |  | 2190 |   | 
        
           |  |  | 2191 |     echo $OUTPUT->header();
 | 
        
           |  |  | 2192 |   | 
        
           |  |  | 2193 |     echo $actionbar;
 | 
        
           |  |  | 2194 |   | 
        
           |  |  | 2195 |     // Print any notices
 | 
        
           |  |  | 2196 |   | 
        
           |  |  | 2197 |     if (!empty($displaynoticegood)) {
 | 
        
           |  |  | 2198 |         echo $OUTPUT->notification($displaynoticegood, 'notifysuccess');    // good (usually green)
 | 
        
           |  |  | 2199 |     } else if (!empty($displaynoticebad)) {
 | 
        
           |  |  | 2200 |         echo $OUTPUT->notification($displaynoticebad);                     // bad (usuually red)
 | 
        
           |  |  | 2201 |     }
 | 
        
           |  |  | 2202 | }
 | 
        
           |  |  | 2203 |   | 
        
           |  |  | 2204 | /**
 | 
        
           |  |  | 2205 |  * Can user add more entries?
 | 
        
           |  |  | 2206 |  *
 | 
        
           |  |  | 2207 |  * @param object $data
 | 
        
           |  |  | 2208 |  * @param mixed $currentgroup
 | 
        
           |  |  | 2209 |  * @param int $groupmode
 | 
        
           |  |  | 2210 |  * @param stdClass $context
 | 
        
           |  |  | 2211 |  * @return bool
 | 
        
           |  |  | 2212 |  */
 | 
        
           |  |  | 2213 | function data_user_can_add_entry($data, $currentgroup, $groupmode, $context = null) {
 | 
        
           |  |  | 2214 |     global $DB;
 | 
        
           |  |  | 2215 |   | 
        
           |  |  | 2216 |     // Don't let add entry to a database that has no fields.
 | 
        
           |  |  | 2217 |     if (!$DB->record_exists('data_fields', ['dataid' => $data->id])) {
 | 
        
           |  |  | 2218 |         return false;
 | 
        
           |  |  | 2219 |     }
 | 
        
           |  |  | 2220 |   | 
        
           |  |  | 2221 |     if (empty($context)) {
 | 
        
           |  |  | 2222 |         $cm = get_coursemodule_from_instance('data', $data->id, 0, false, MUST_EXIST);
 | 
        
           |  |  | 2223 |         $context = context_module::instance($cm->id);
 | 
        
           |  |  | 2224 |     }
 | 
        
           |  |  | 2225 |   | 
        
           |  |  | 2226 |     if (has_capability('mod/data:manageentries', $context)) {
 | 
        
           |  |  | 2227 |         // no entry limits apply if user can manage
 | 
        
           |  |  | 2228 |   | 
        
           |  |  | 2229 |     } else if (!has_capability('mod/data:writeentry', $context)) {
 | 
        
           |  |  | 2230 |         return false;
 | 
        
           |  |  | 2231 |   | 
        
           |  |  | 2232 |     } else if (data_atmaxentries($data)) {
 | 
        
           |  |  | 2233 |         return false;
 | 
        
           |  |  | 2234 |     } else if (data_in_readonly_period($data)) {
 | 
        
           |  |  | 2235 |         // Check whether we're in a read-only period
 | 
        
           |  |  | 2236 |         return false;
 | 
        
           |  |  | 2237 |     }
 | 
        
           |  |  | 2238 |   | 
        
           |  |  | 2239 |     if (!$groupmode or has_capability('moodle/site:accessallgroups', $context)) {
 | 
        
           |  |  | 2240 |         return true;
 | 
        
           |  |  | 2241 |     }
 | 
        
           |  |  | 2242 |   | 
        
           |  |  | 2243 |     if ($currentgroup) {
 | 
        
           |  |  | 2244 |         return groups_is_member($currentgroup);
 | 
        
           |  |  | 2245 |     } else {
 | 
        
           |  |  | 2246 |         //else it might be group 0 in visible mode
 | 
        
           |  |  | 2247 |         if ($groupmode == VISIBLEGROUPS){
 | 
        
           |  |  | 2248 |             return true;
 | 
        
           |  |  | 2249 |         } else {
 | 
        
           |  |  | 2250 |             return false;
 | 
        
           |  |  | 2251 |         }
 | 
        
           |  |  | 2252 |     }
 | 
        
           |  |  | 2253 | }
 | 
        
           |  |  | 2254 |   | 
        
           |  |  | 2255 | /**
 | 
        
           |  |  | 2256 |  * Check whether the current user is allowed to manage the given record considering manageentries capability,
 | 
        
           |  |  | 2257 |  * data_in_readonly_period() result, ownership (determined by data_isowner()) and manageapproved setting.
 | 
        
           |  |  | 2258 |  * @param mixed $record record object or id
 | 
        
           |  |  | 2259 |  * @param object $data data object
 | 
        
           |  |  | 2260 |  * @param object $context context object
 | 
        
           |  |  | 2261 |  * @return bool returns true if the user is allowd to edit the entry, false otherwise
 | 
        
           |  |  | 2262 |  */
 | 
        
           |  |  | 2263 | function data_user_can_manage_entry($record, $data, $context) {
 | 
        
           |  |  | 2264 |     global $DB;
 | 
        
           |  |  | 2265 |   | 
        
           |  |  | 2266 |     if (has_capability('mod/data:manageentries', $context)) {
 | 
        
           |  |  | 2267 |         return true;
 | 
        
           |  |  | 2268 |     }
 | 
        
           |  |  | 2269 |   | 
        
           |  |  | 2270 |     // Check whether this activity is read-only at present.
 | 
        
           |  |  | 2271 |     $readonly = data_in_readonly_period($data);
 | 
        
           |  |  | 2272 |   | 
        
           |  |  | 2273 |     if (!$readonly) {
 | 
        
           |  |  | 2274 |         // Get record object from db if just id given like in data_isowner.
 | 
        
           |  |  | 2275 |         // ...done before calling data_isowner() to avoid querying db twice.
 | 
        
           |  |  | 2276 |         if (!is_object($record)) {
 | 
        
           |  |  | 2277 |             if (!$record = $DB->get_record('data_records', array('id' => $record))) {
 | 
        
           |  |  | 2278 |                 return false;
 | 
        
           |  |  | 2279 |             }
 | 
        
           |  |  | 2280 |         }
 | 
        
           |  |  | 2281 |         if (data_isowner($record)) {
 | 
        
           |  |  | 2282 |             if ($data->approval && $record->approved) {
 | 
        
           |  |  | 2283 |                 return $data->manageapproved == 1;
 | 
        
           |  |  | 2284 |             } else {
 | 
        
           |  |  | 2285 |                 return true;
 | 
        
           |  |  | 2286 |             }
 | 
        
           |  |  | 2287 |         }
 | 
        
           |  |  | 2288 |     }
 | 
        
           |  |  | 2289 |   | 
        
           |  |  | 2290 |     return false;
 | 
        
           |  |  | 2291 | }
 | 
        
           |  |  | 2292 |   | 
        
           |  |  | 2293 | /**
 | 
        
           |  |  | 2294 |  * Check whether the specified database activity is currently in a read-only period
 | 
        
           |  |  | 2295 |  *
 | 
        
           |  |  | 2296 |  * @param object $data
 | 
        
           |  |  | 2297 |  * @return bool returns true if the time fields in $data indicate a read-only period; false otherwise
 | 
        
           |  |  | 2298 |  */
 | 
        
           |  |  | 2299 | function data_in_readonly_period($data) {
 | 
        
           |  |  | 2300 |     $now = time();
 | 
        
           |  |  | 2301 |     if (!$data->timeviewfrom && !$data->timeviewto) {
 | 
        
           |  |  | 2302 |         return false;
 | 
        
           |  |  | 2303 |     } else if (($data->timeviewfrom && $now < $data->timeviewfrom) || ($data->timeviewto && $now > $data->timeviewto)) {
 | 
        
           |  |  | 2304 |         return false;
 | 
        
           |  |  | 2305 |     }
 | 
        
           |  |  | 2306 |     return true;
 | 
        
           |  |  | 2307 | }
 | 
        
           |  |  | 2308 |   | 
        
           |  |  | 2309 | /**
 | 
        
           |  |  | 2310 |  * @global object
 | 
        
           |  |  | 2311 |  * @global object
 | 
        
           |  |  | 2312 |  * @param object $course
 | 
        
           |  |  | 2313 |  * @param int $userid
 | 
        
           |  |  | 2314 |  * @param string $shortname
 | 
        
           |  |  | 2315 |  * @return string
 | 
        
           |  |  | 2316 |  */
 | 
        
           |  |  | 2317 | function data_preset_path($course, $userid, $shortname) {
 | 
        
           |  |  | 2318 |     global $USER, $CFG;
 | 
        
           |  |  | 2319 |   | 
        
           |  |  | 2320 |     $context = context_course::instance($course->id);
 | 
        
           |  |  | 2321 |   | 
        
           |  |  | 2322 |     $userid = (int)$userid;
 | 
        
           |  |  | 2323 |   | 
        
           |  |  | 2324 |     $path = null;
 | 
        
           |  |  | 2325 |     if ($userid > 0 && ($userid == $USER->id || has_capability('mod/data:viewalluserpresets', $context))) {
 | 
        
           |  |  | 2326 |         $path = $CFG->dataroot.'/data/preset/'.$userid.'/'.$shortname;
 | 
        
           |  |  | 2327 |     } else if ($userid == 0) {
 | 
        
           |  |  | 2328 |         $path = $CFG->dirroot.'/mod/data/preset/'.$shortname;
 | 
        
           |  |  | 2329 |     } else if ($userid < 0) {
 | 
        
           |  |  | 2330 |         $path = $CFG->tempdir.'/data/'.-$userid.'/'.$shortname;
 | 
        
           |  |  | 2331 |     }
 | 
        
           |  |  | 2332 |   | 
        
           |  |  | 2333 |     return $path;
 | 
        
           |  |  | 2334 | }
 | 
        
           |  |  | 2335 |   | 
        
           |  |  | 2336 | /**
 | 
        
           |  |  | 2337 |  * Implementation of the function for printing the form elements that control
 | 
        
           |  |  | 2338 |  * whether the course reset functionality affects the data.
 | 
        
           |  |  | 2339 |  *
 | 
        
           |  |  | 2340 |  * @param MoodleQuickForm $mform form passed by reference
 | 
        
           |  |  | 2341 |  */
 | 
        
           |  |  | 2342 | function data_reset_course_form_definition(&$mform) {
 | 
        
           |  |  | 2343 |     $mform->addElement('header', 'dataheader', get_string('modulenameplural', 'data'));
 | 
        
           | 1441 | ariadna | 2344 |     $mform->addElement('static', 'datadelete', get_string('delete'));
 | 
        
           | 1 | efrain | 2345 |     $mform->addElement('checkbox', 'reset_data', get_string('deleteallentries','data'));
 | 
        
           |  |  | 2346 |   | 
        
           |  |  | 2347 |     $mform->addElement('checkbox', 'reset_data_notenrolled', get_string('deletenotenrolled', 'data'));
 | 
        
           |  |  | 2348 |     $mform->disabledIf('reset_data_notenrolled', 'reset_data', 'checked');
 | 
        
           |  |  | 2349 |   | 
        
           |  |  | 2350 |     $mform->addElement('checkbox', 'reset_data_ratings', get_string('deleteallratings'));
 | 
        
           |  |  | 2351 |     $mform->disabledIf('reset_data_ratings', 'reset_data', 'checked');
 | 
        
           |  |  | 2352 |   | 
        
           |  |  | 2353 |     $mform->addElement('checkbox', 'reset_data_comments', get_string('deleteallcomments'));
 | 
        
           |  |  | 2354 |     $mform->disabledIf('reset_data_comments', 'reset_data', 'checked');
 | 
        
           |  |  | 2355 |   | 
        
           |  |  | 2356 |     $mform->addElement('checkbox', 'reset_data_tags', get_string('removealldatatags', 'data'));
 | 
        
           |  |  | 2357 |     $mform->disabledIf('reset_data_tags', 'reset_data', 'checked');
 | 
        
           |  |  | 2358 | }
 | 
        
           |  |  | 2359 |   | 
        
           |  |  | 2360 | /**
 | 
        
           |  |  | 2361 |  * Course reset form defaults.
 | 
        
           |  |  | 2362 |  * @return array
 | 
        
           |  |  | 2363 |  */
 | 
        
           |  |  | 2364 | function data_reset_course_form_defaults($course) {
 | 
        
           |  |  | 2365 |     return array('reset_data'=>0, 'reset_data_ratings'=>1, 'reset_data_comments'=>1, 'reset_data_notenrolled'=>0);
 | 
        
           |  |  | 2366 | }
 | 
        
           |  |  | 2367 |   | 
        
           |  |  | 2368 | /**
 | 
        
           |  |  | 2369 |  * Removes all grades from gradebook
 | 
        
           |  |  | 2370 |  *
 | 
        
           |  |  | 2371 |  * @global object
 | 
        
           |  |  | 2372 |  * @global object
 | 
        
           |  |  | 2373 |  * @param int $courseid
 | 
        
           |  |  | 2374 |  * @param string $type optional type
 | 
        
           |  |  | 2375 |  */
 | 
        
           |  |  | 2376 | function data_reset_gradebook($courseid, $type='') {
 | 
        
           |  |  | 2377 |     global $CFG, $DB;
 | 
        
           |  |  | 2378 |   | 
        
           |  |  | 2379 |     $sql = "SELECT d.*, cm.idnumber as cmidnumber, d.course as courseid
 | 
        
           |  |  | 2380 |               FROM {data} d, {course_modules} cm, {modules} m
 | 
        
           |  |  | 2381 |              WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id AND d.course=?";
 | 
        
           |  |  | 2382 |   | 
        
           |  |  | 2383 |     if ($datas = $DB->get_records_sql($sql, array($courseid))) {
 | 
        
           |  |  | 2384 |         foreach ($datas as $data) {
 | 
        
           |  |  | 2385 |             data_grade_item_update($data, 'reset');
 | 
        
           |  |  | 2386 |         }
 | 
        
           |  |  | 2387 |     }
 | 
        
           |  |  | 2388 | }
 | 
        
           |  |  | 2389 |   | 
        
           |  |  | 2390 | /**
 | 
        
           |  |  | 2391 |  * Actual implementation of the reset course functionality, delete all the
 | 
        
           |  |  | 2392 |  * data responses for course $data->courseid.
 | 
        
           |  |  | 2393 |  *
 | 
        
           |  |  | 2394 |  * @global object
 | 
        
           |  |  | 2395 |  * @global object
 | 
        
           |  |  | 2396 |  * @param object $data the data submitted from the reset course.
 | 
        
           |  |  | 2397 |  * @return array status array
 | 
        
           |  |  | 2398 |  */
 | 
        
           |  |  | 2399 | function data_reset_userdata($data) {
 | 
        
           |  |  | 2400 |     global $CFG, $DB;
 | 
        
           |  |  | 2401 |     require_once($CFG->libdir.'/filelib.php');
 | 
        
           |  |  | 2402 |     require_once($CFG->dirroot.'/rating/lib.php');
 | 
        
           |  |  | 2403 |   | 
        
           |  |  | 2404 |     $componentstr = get_string('modulenameplural', 'data');
 | 
        
           | 1441 | ariadna | 2405 |     $status = [];
 | 
        
           | 1 | efrain | 2406 |   | 
        
           |  |  | 2407 |     $allrecordssql = "SELECT r.id
 | 
        
           |  |  | 2408 |                         FROM {data_records} r
 | 
        
           |  |  | 2409 |                              INNER JOIN {data} d ON r.dataid = d.id
 | 
        
           |  |  | 2410 |                        WHERE d.course = ?";
 | 
        
           |  |  | 2411 |   | 
        
           |  |  | 2412 |     $alldatassql = "SELECT d.id
 | 
        
           |  |  | 2413 |                       FROM {data} d
 | 
        
           |  |  | 2414 |                      WHERE d.course=?";
 | 
        
           |  |  | 2415 |   | 
        
           |  |  | 2416 |     $rm = new rating_manager();
 | 
        
           |  |  | 2417 |     $ratingdeloptions = new stdClass;
 | 
        
           |  |  | 2418 |     $ratingdeloptions->component = 'mod_data';
 | 
        
           |  |  | 2419 |     $ratingdeloptions->ratingarea = 'entry';
 | 
        
           |  |  | 2420 |   | 
        
           |  |  | 2421 |     // Set the file storage - may need it to remove files later.
 | 
        
           |  |  | 2422 |     $fs = get_file_storage();
 | 
        
           |  |  | 2423 |   | 
        
           | 1441 | ariadna | 2424 |     // Delete entries if requested.
 | 
        
           | 1 | efrain | 2425 |     if (!empty($data->reset_data)) {
 | 
        
           | 1441 | ariadna | 2426 |         $DB->delete_records_select('comments', "itemid IN ($allrecordssql) AND commentarea='database_entry'", [$data->courseid]);
 | 
        
           |  |  | 2427 |         $DB->delete_records_select('data_content', "recordid IN ($allrecordssql)", [$data->courseid]);
 | 
        
           |  |  | 2428 |         $DB->delete_records_select('data_records', "dataid IN ($alldatassql)", [$data->courseid]);
 | 
        
           | 1 | efrain | 2429 |   | 
        
           | 1441 | ariadna | 2430 |         if ($datas = $DB->get_records_sql($alldatassql, [$data->courseid])) {
 | 
        
           | 1 | efrain | 2431 |             foreach ($datas as $dataid=>$unused) {
 | 
        
           |  |  | 2432 |                 if (!$cm = get_coursemodule_from_instance('data', $dataid)) {
 | 
        
           |  |  | 2433 |                     continue;
 | 
        
           |  |  | 2434 |                 }
 | 
        
           |  |  | 2435 |                 $datacontext = context_module::instance($cm->id);
 | 
        
           |  |  | 2436 |   | 
        
           |  |  | 2437 |                 // Delete any files that may exist.
 | 
        
           |  |  | 2438 |                 $fs->delete_area_files($datacontext->id, 'mod_data', 'content');
 | 
        
           |  |  | 2439 |   | 
        
           |  |  | 2440 |                 $ratingdeloptions->contextid = $datacontext->id;
 | 
        
           |  |  | 2441 |                 $rm->delete_ratings($ratingdeloptions);
 | 
        
           |  |  | 2442 |   | 
        
           |  |  | 2443 |                 core_tag_tag::delete_instances('mod_data', null, $datacontext->id);
 | 
        
           |  |  | 2444 |             }
 | 
        
           |  |  | 2445 |         }
 | 
        
           |  |  | 2446 |   | 
        
           |  |  | 2447 |         if (empty($data->reset_gradebook_grades)) {
 | 
        
           | 1441 | ariadna | 2448 |             // Remove all grades from gradebook.
 | 
        
           | 1 | efrain | 2449 |             data_reset_gradebook($data->courseid);
 | 
        
           |  |  | 2450 |         }
 | 
        
           | 1441 | ariadna | 2451 |         $status[] = [
 | 
        
           |  |  | 2452 |             'component' => $componentstr,
 | 
        
           |  |  | 2453 |             'item' => get_string('deleteallentries', 'data'),
 | 
        
           |  |  | 2454 |             'error' => false,
 | 
        
           |  |  | 2455 |         ];
 | 
        
           | 1 | efrain | 2456 |     }
 | 
        
           |  |  | 2457 |   | 
        
           | 1441 | ariadna | 2458 |     // Remove entries by users not enrolled into course.
 | 
        
           | 1 | efrain | 2459 |     if (!empty($data->reset_data_notenrolled)) {
 | 
        
           |  |  | 2460 |         $recordssql = "SELECT r.id, r.userid, r.dataid, u.id AS userexists, u.deleted AS userdeleted
 | 
        
           |  |  | 2461 |                          FROM {data_records} r
 | 
        
           |  |  | 2462 |                               JOIN {data} d ON r.dataid = d.id
 | 
        
           |  |  | 2463 |                               LEFT JOIN {user} u ON r.userid = u.id
 | 
        
           |  |  | 2464 |                         WHERE d.course = ? AND r.userid > 0";
 | 
        
           |  |  | 2465 |   | 
        
           |  |  | 2466 |         $course_context = context_course::instance($data->courseid);
 | 
        
           | 1441 | ariadna | 2467 |         $notenrolled = [];
 | 
        
           |  |  | 2468 |         $fields = [];
 | 
        
           |  |  | 2469 |         $rs = $DB->get_recordset_sql($recordssql, [$data->courseid]);
 | 
        
           | 1 | efrain | 2470 |         foreach ($rs as $record) {
 | 
        
           |  |  | 2471 |             if (array_key_exists($record->userid, $notenrolled) or !$record->userexists or $record->userdeleted
 | 
        
           |  |  | 2472 |               or !is_enrolled($course_context, $record->userid)) {
 | 
        
           | 1441 | ariadna | 2473 |                 // Delete ratings.
 | 
        
           | 1 | efrain | 2474 |                 if (!$cm = get_coursemodule_from_instance('data', $record->dataid)) {
 | 
        
           |  |  | 2475 |                     continue;
 | 
        
           |  |  | 2476 |                 }
 | 
        
           |  |  | 2477 |                 $datacontext = context_module::instance($cm->id);
 | 
        
           |  |  | 2478 |                 $ratingdeloptions->contextid = $datacontext->id;
 | 
        
           |  |  | 2479 |                 $ratingdeloptions->itemid = $record->id;
 | 
        
           |  |  | 2480 |                 $rm->delete_ratings($ratingdeloptions);
 | 
        
           |  |  | 2481 |   | 
        
           |  |  | 2482 |                 // Delete any files that may exist.
 | 
        
           | 1441 | ariadna | 2483 |                 if ($contents = $DB->get_records('data_content', ['recordid' => $record->id], '', 'id')) {
 | 
        
           | 1 | efrain | 2484 |                     foreach ($contents as $content) {
 | 
        
           |  |  | 2485 |                         $fs->delete_area_files($datacontext->id, 'mod_data', 'content', $content->id);
 | 
        
           |  |  | 2486 |                     }
 | 
        
           |  |  | 2487 |                 }
 | 
        
           |  |  | 2488 |                 $notenrolled[$record->userid] = true;
 | 
        
           |  |  | 2489 |   | 
        
           |  |  | 2490 |                 core_tag_tag::remove_all_item_tags('mod_data', 'data_records', $record->id);
 | 
        
           |  |  | 2491 |   | 
        
           | 1441 | ariadna | 2492 |                 $DB->delete_records('comments', ['itemid' => $record->id, 'commentarea' => 'database_entry']);
 | 
        
           |  |  | 2493 |                 $DB->delete_records('data_content', ['recordid' => $record->id]);
 | 
        
           |  |  | 2494 |                 $DB->delete_records('data_records', ['id' => $record->id]);
 | 
        
           | 1 | efrain | 2495 |             }
 | 
        
           |  |  | 2496 |         }
 | 
        
           |  |  | 2497 |         $rs->close();
 | 
        
           | 1441 | ariadna | 2498 |         $status[] = [
 | 
        
           |  |  | 2499 |             'component' => $componentstr,
 | 
        
           |  |  | 2500 |             'item' => get_string('deletenotenrolled', 'data'),
 | 
        
           |  |  | 2501 |             'error' => false,
 | 
        
           |  |  | 2502 |         ];
 | 
        
           | 1 | efrain | 2503 |     }
 | 
        
           |  |  | 2504 |   | 
        
           | 1441 | ariadna | 2505 |     // Remove all ratings.
 | 
        
           | 1 | efrain | 2506 |     if (!empty($data->reset_data_ratings)) {
 | 
        
           | 1441 | ariadna | 2507 |         if ($datas = $DB->get_records_sql($alldatassql, [$data->courseid])) {
 | 
        
           | 1 | efrain | 2508 |             foreach ($datas as $dataid=>$unused) {
 | 
        
           |  |  | 2509 |                 if (!$cm = get_coursemodule_from_instance('data', $dataid)) {
 | 
        
           |  |  | 2510 |                     continue;
 | 
        
           |  |  | 2511 |                 }
 | 
        
           |  |  | 2512 |                 $datacontext = context_module::instance($cm->id);
 | 
        
           |  |  | 2513 |   | 
        
           |  |  | 2514 |                 $ratingdeloptions->contextid = $datacontext->id;
 | 
        
           |  |  | 2515 |                 $rm->delete_ratings($ratingdeloptions);
 | 
        
           |  |  | 2516 |             }
 | 
        
           |  |  | 2517 |         }
 | 
        
           |  |  | 2518 |   | 
        
           |  |  | 2519 |         if (empty($data->reset_gradebook_grades)) {
 | 
        
           | 1441 | ariadna | 2520 |             // Remove all grades from gradebook.
 | 
        
           | 1 | efrain | 2521 |             data_reset_gradebook($data->courseid);
 | 
        
           |  |  | 2522 |         }
 | 
        
           |  |  | 2523 |   | 
        
           | 1441 | ariadna | 2524 |         $status[] = [
 | 
        
           |  |  | 2525 |             'component' => $componentstr,
 | 
        
           |  |  | 2526 |             'item' => get_string('deleteallratings'),
 | 
        
           |  |  | 2527 |             'error' => false,
 | 
        
           |  |  | 2528 |         ];
 | 
        
           | 1 | efrain | 2529 |     }
 | 
        
           |  |  | 2530 |   | 
        
           | 1441 | ariadna | 2531 |     // Remove all comments.
 | 
        
           | 1 | efrain | 2532 |     if (!empty($data->reset_data_comments)) {
 | 
        
           | 1441 | ariadna | 2533 |         $DB->delete_records_select('comments', "itemid IN ($allrecordssql) AND commentarea='database_entry'", [$data->courseid]);
 | 
        
           |  |  | 2534 |         $status[] = [
 | 
        
           |  |  | 2535 |             'component' => $componentstr,
 | 
        
           |  |  | 2536 |             'item' => get_string('deleteallcomments'),
 | 
        
           |  |  | 2537 |             'error' => false,
 | 
        
           |  |  | 2538 |         ];
 | 
        
           | 1 | efrain | 2539 |     }
 | 
        
           |  |  | 2540 |   | 
        
           |  |  | 2541 |     // Remove all the tags.
 | 
        
           |  |  | 2542 |     if (!empty($data->reset_data_tags)) {
 | 
        
           | 1441 | ariadna | 2543 |         if ($datas = $DB->get_records_sql($alldatassql, [$data->courseid])) {
 | 
        
           | 1 | efrain | 2544 |             foreach ($datas as $dataid => $unused) {
 | 
        
           |  |  | 2545 |                 if (!$cm = get_coursemodule_from_instance('data', $dataid)) {
 | 
        
           |  |  | 2546 |                     continue;
 | 
        
           |  |  | 2547 |                 }
 | 
        
           |  |  | 2548 |   | 
        
           |  |  | 2549 |                 $context = context_module::instance($cm->id);
 | 
        
           |  |  | 2550 |                 core_tag_tag::delete_instances('mod_data', null, $context->id);
 | 
        
           |  |  | 2551 |   | 
        
           |  |  | 2552 |             }
 | 
        
           |  |  | 2553 |         }
 | 
        
           | 1441 | ariadna | 2554 |         $status[] = [
 | 
        
           |  |  | 2555 |             'component' => $componentstr,
 | 
        
           |  |  | 2556 |             'item' => get_string('removealldatatags', 'data'),
 | 
        
           |  |  | 2557 |             'error' => false,
 | 
        
           |  |  | 2558 |         ];
 | 
        
           | 1 | efrain | 2559 |     }
 | 
        
           |  |  | 2560 |   | 
        
           | 1441 | ariadna | 2561 |     // Updating dates - shift may be negative too.
 | 
        
           | 1 | efrain | 2562 |     if ($data->timeshift) {
 | 
        
           |  |  | 2563 |         // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
 | 
        
           |  |  | 2564 |         // See MDL-9367.
 | 
        
           | 1441 | ariadna | 2565 |         shift_course_mod_dates(
 | 
        
           |  |  | 2566 |             'data',
 | 
        
           |  |  | 2567 |             [
 | 
        
           |  |  | 2568 |                 'timeavailablefrom',
 | 
        
           |  |  | 2569 |                 'timeavailableto',
 | 
        
           |  |  | 2570 |                 'timeviewfrom',
 | 
        
           |  |  | 2571 |                 'timeviewto',
 | 
        
           |  |  | 2572 |                 'assesstimestart',
 | 
        
           |  |  | 2573 |                 'assesstimefinish',
 | 
        
           |  |  | 2574 |             ],
 | 
        
           |  |  | 2575 |             $data->timeshift,
 | 
        
           |  |  | 2576 |             $data->courseid,
 | 
        
           |  |  | 2577 |         );
 | 
        
           |  |  | 2578 |         $status[] = [
 | 
        
           |  |  | 2579 |             'component' => $componentstr,
 | 
        
           |  |  | 2580 |             'item' => get_string('date'),
 | 
        
           |  |  | 2581 |             'error' => false,
 | 
        
           |  |  | 2582 |         ];
 | 
        
           | 1 | efrain | 2583 |     }
 | 
        
           |  |  | 2584 |   | 
        
           |  |  | 2585 |     return $status;
 | 
        
           |  |  | 2586 | }
 | 
        
           |  |  | 2587 |   | 
        
           |  |  | 2588 | /**
 | 
        
           |  |  | 2589 |  * Returns all other caps used in module
 | 
        
           |  |  | 2590 |  *
 | 
        
           |  |  | 2591 |  * @return array
 | 
        
           |  |  | 2592 |  */
 | 
        
           |  |  | 2593 | function data_get_extra_capabilities() {
 | 
        
           |  |  | 2594 |     return ['moodle/rating:view', 'moodle/rating:viewany', 'moodle/rating:viewall', 'moodle/rating:rate',
 | 
        
           |  |  | 2595 |             'moodle/comment:view', 'moodle/comment:post', 'moodle/comment:delete'];
 | 
        
           |  |  | 2596 | }
 | 
        
           |  |  | 2597 |   | 
        
           |  |  | 2598 | /**
 | 
        
           |  |  | 2599 |  * @param string $feature FEATURE_xx constant for requested feature
 | 
        
           |  |  | 2600 |  * @return mixed True if module supports feature, false if not, null if doesn't know or string for the module purpose.
 | 
        
           |  |  | 2601 |  */
 | 
        
           |  |  | 2602 | function data_supports($feature) {
 | 
        
           |  |  | 2603 |     switch($feature) {
 | 
        
           |  |  | 2604 |         case FEATURE_GROUPS:                  return true;
 | 
        
           |  |  | 2605 |         case FEATURE_GROUPINGS:               return true;
 | 
        
           |  |  | 2606 |         case FEATURE_MOD_INTRO:               return true;
 | 
        
           |  |  | 2607 |         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
 | 
        
           |  |  | 2608 |         case FEATURE_COMPLETION_HAS_RULES:    return true;
 | 
        
           |  |  | 2609 |         case FEATURE_GRADE_HAS_GRADE:         return true;
 | 
        
           |  |  | 2610 |         case FEATURE_GRADE_OUTCOMES:          return true;
 | 
        
           |  |  | 2611 |         case FEATURE_RATE:                    return true;
 | 
        
           |  |  | 2612 |         case FEATURE_BACKUP_MOODLE2:          return true;
 | 
        
           |  |  | 2613 |         case FEATURE_SHOW_DESCRIPTION:        return true;
 | 
        
           |  |  | 2614 |         case FEATURE_COMMENT:                 return true;
 | 
        
           |  |  | 2615 |         case FEATURE_MOD_PURPOSE:             return MOD_PURPOSE_COLLABORATION;
 | 
        
           |  |  | 2616 |   | 
        
           |  |  | 2617 |         default: return null;
 | 
        
           |  |  | 2618 |     }
 | 
        
           |  |  | 2619 | }
 | 
        
           |  |  | 2620 |   | 
        
           |  |  | 2621 | ////////////////////////////////////////////////////////////////////////////////
 | 
        
           |  |  | 2622 | // File API                                                                   //
 | 
        
           |  |  | 2623 | ////////////////////////////////////////////////////////////////////////////////
 | 
        
           |  |  | 2624 |   | 
        
           |  |  | 2625 | /**
 | 
        
           |  |  | 2626 |  * Lists all browsable file areas
 | 
        
           |  |  | 2627 |  *
 | 
        
           |  |  | 2628 |  * @package  mod_data
 | 
        
           |  |  | 2629 |  * @category files
 | 
        
           |  |  | 2630 |  * @param stdClass $course course object
 | 
        
           |  |  | 2631 |  * @param stdClass $cm course module object
 | 
        
           |  |  | 2632 |  * @param stdClass $context context object
 | 
        
           |  |  | 2633 |  * @return array
 | 
        
           |  |  | 2634 |  */
 | 
        
           |  |  | 2635 | function data_get_file_areas($course, $cm, $context) {
 | 
        
           |  |  | 2636 |     return array('content' => get_string('areacontent', 'mod_data'));
 | 
        
           |  |  | 2637 | }
 | 
        
           |  |  | 2638 |   | 
        
           |  |  | 2639 | /**
 | 
        
           |  |  | 2640 |  * File browsing support for data module.
 | 
        
           |  |  | 2641 |  *
 | 
        
           |  |  | 2642 |  * @param file_browser $browser
 | 
        
           |  |  | 2643 |  * @param array $areas
 | 
        
           |  |  | 2644 |  * @param stdClass $course
 | 
        
           |  |  | 2645 |  * @param cm_info $cm
 | 
        
           |  |  | 2646 |  * @param context $context
 | 
        
           |  |  | 2647 |  * @param string $filearea
 | 
        
           |  |  | 2648 |  * @param int $itemid
 | 
        
           |  |  | 2649 |  * @param string $filepath
 | 
        
           |  |  | 2650 |  * @param string $filename
 | 
        
           |  |  | 2651 |  * @return file_info_stored file_info_stored instance or null if not found
 | 
        
           |  |  | 2652 |  */
 | 
        
           |  |  | 2653 | function data_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
 | 
        
           |  |  | 2654 |     global $CFG, $DB, $USER;
 | 
        
           |  |  | 2655 |   | 
        
           |  |  | 2656 |     if ($context->contextlevel != CONTEXT_MODULE) {
 | 
        
           |  |  | 2657 |         return null;
 | 
        
           |  |  | 2658 |     }
 | 
        
           |  |  | 2659 |   | 
        
           |  |  | 2660 |     if (!isset($areas[$filearea])) {
 | 
        
           |  |  | 2661 |         return null;
 | 
        
           |  |  | 2662 |     }
 | 
        
           |  |  | 2663 |   | 
        
           |  |  | 2664 |     if (is_null($itemid)) {
 | 
        
           |  |  | 2665 |         require_once($CFG->dirroot.'/mod/data/locallib.php');
 | 
        
           |  |  | 2666 |         return new data_file_info_container($browser, $course, $cm, $context, $areas, $filearea);
 | 
        
           |  |  | 2667 |     }
 | 
        
           |  |  | 2668 |   | 
        
           |  |  | 2669 |     if (!$content = $DB->get_record('data_content', array('id'=>$itemid))) {
 | 
        
           |  |  | 2670 |         return null;
 | 
        
           |  |  | 2671 |     }
 | 
        
           |  |  | 2672 |   | 
        
           |  |  | 2673 |     if (!$field = $DB->get_record('data_fields', array('id'=>$content->fieldid))) {
 | 
        
           |  |  | 2674 |         return null;
 | 
        
           |  |  | 2675 |     }
 | 
        
           |  |  | 2676 |   | 
        
           |  |  | 2677 |     if (!$record = $DB->get_record('data_records', array('id'=>$content->recordid))) {
 | 
        
           |  |  | 2678 |         return null;
 | 
        
           |  |  | 2679 |     }
 | 
        
           |  |  | 2680 |   | 
        
           |  |  | 2681 |     if (!$data = $DB->get_record('data', array('id'=>$field->dataid))) {
 | 
        
           |  |  | 2682 |         return null;
 | 
        
           |  |  | 2683 |     }
 | 
        
           |  |  | 2684 |   | 
        
           |  |  | 2685 |     //check if approved
 | 
        
           |  |  | 2686 |     if ($data->approval and !$record->approved and !data_isowner($record) and !has_capability('mod/data:approve', $context)) {
 | 
        
           |  |  | 2687 |         return null;
 | 
        
           |  |  | 2688 |     }
 | 
        
           |  |  | 2689 |   | 
        
           |  |  | 2690 |     // group access
 | 
        
           |  |  | 2691 |     if ($record->groupid) {
 | 
        
           |  |  | 2692 |         $groupmode = groups_get_activity_groupmode($cm, $course);
 | 
        
           |  |  | 2693 |         if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
 | 
        
           |  |  | 2694 |             if (!groups_is_member($record->groupid)) {
 | 
        
           |  |  | 2695 |                 return null;
 | 
        
           |  |  | 2696 |             }
 | 
        
           |  |  | 2697 |         }
 | 
        
           |  |  | 2698 |     }
 | 
        
           |  |  | 2699 |   | 
        
           |  |  | 2700 |     $fieldobj = data_get_field($field, $data, $cm);
 | 
        
           |  |  | 2701 |   | 
        
           |  |  | 2702 |     $filepath = is_null($filepath) ? '/' : $filepath;
 | 
        
           |  |  | 2703 |     $filename = is_null($filename) ? '.' : $filename;
 | 
        
           |  |  | 2704 |     if (!$fieldobj->file_ok($filepath.$filename)) {
 | 
        
           |  |  | 2705 |         return null;
 | 
        
           |  |  | 2706 |     }
 | 
        
           |  |  | 2707 |   | 
        
           |  |  | 2708 |     $fs = get_file_storage();
 | 
        
           |  |  | 2709 |     if (!($storedfile = $fs->get_file($context->id, 'mod_data', $filearea, $itemid, $filepath, $filename))) {
 | 
        
           |  |  | 2710 |         return null;
 | 
        
           |  |  | 2711 |     }
 | 
        
           |  |  | 2712 |   | 
        
           |  |  | 2713 |     // Checks to see if the user can manage files or is the owner.
 | 
        
           |  |  | 2714 |     // TODO MDL-33805 - Do not use userid here and move the capability check above.
 | 
        
           |  |  | 2715 |     if (!has_capability('moodle/course:managefiles', $context) && $storedfile->get_userid() != $USER->id) {
 | 
        
           |  |  | 2716 |         return null;
 | 
        
           |  |  | 2717 |     }
 | 
        
           |  |  | 2718 |   | 
        
           |  |  | 2719 |     $urlbase = $CFG->wwwroot.'/pluginfile.php';
 | 
        
           |  |  | 2720 |   | 
        
           |  |  | 2721 |     return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemid, true, true, false, false);
 | 
        
           |  |  | 2722 | }
 | 
        
           |  |  | 2723 |   | 
        
           |  |  | 2724 | /**
 | 
        
           |  |  | 2725 |  * Serves the data attachments. Implements needed access control ;-)
 | 
        
           |  |  | 2726 |  *
 | 
        
           |  |  | 2727 |  * @package  mod_data
 | 
        
           |  |  | 2728 |  * @category files
 | 
        
           |  |  | 2729 |  * @param stdClass $course course object
 | 
        
           |  |  | 2730 |  * @param stdClass $cm course module object
 | 
        
           |  |  | 2731 |  * @param stdClass $context context object
 | 
        
           |  |  | 2732 |  * @param string $filearea file area
 | 
        
           |  |  | 2733 |  * @param array $args extra arguments
 | 
        
           |  |  | 2734 |  * @param bool $forcedownload whether or not force download
 | 
        
           |  |  | 2735 |  * @param array $options additional options affecting the file serving
 | 
        
           |  |  | 2736 |  * @return bool false if file not found, does not return if found - justsend the file
 | 
        
           |  |  | 2737 |  */
 | 
        
           |  |  | 2738 | function data_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
 | 
        
           |  |  | 2739 |     global $CFG, $DB;
 | 
        
           |  |  | 2740 |   | 
        
           |  |  | 2741 |     if ($context->contextlevel != CONTEXT_MODULE) {
 | 
        
           |  |  | 2742 |         return false;
 | 
        
           |  |  | 2743 |     }
 | 
        
           |  |  | 2744 |   | 
        
           |  |  | 2745 |     require_course_login($course, true, $cm);
 | 
        
           |  |  | 2746 |   | 
        
           |  |  | 2747 |     if ($filearea === 'content') {
 | 
        
           |  |  | 2748 |         $contentid = (int)array_shift($args);
 | 
        
           |  |  | 2749 |   | 
        
           |  |  | 2750 |         if (!$content = $DB->get_record('data_content', array('id'=>$contentid))) {
 | 
        
           |  |  | 2751 |             return false;
 | 
        
           |  |  | 2752 |         }
 | 
        
           |  |  | 2753 |   | 
        
           |  |  | 2754 |         if (!$field = $DB->get_record('data_fields', array('id'=>$content->fieldid))) {
 | 
        
           |  |  | 2755 |             return false;
 | 
        
           |  |  | 2756 |         }
 | 
        
           |  |  | 2757 |   | 
        
           |  |  | 2758 |         if (!$record = $DB->get_record('data_records', array('id'=>$content->recordid))) {
 | 
        
           |  |  | 2759 |             return false;
 | 
        
           |  |  | 2760 |         }
 | 
        
           |  |  | 2761 |   | 
        
           |  |  | 2762 |         if (!$data = $DB->get_record('data', array('id'=>$field->dataid))) {
 | 
        
           |  |  | 2763 |             return false;
 | 
        
           |  |  | 2764 |         }
 | 
        
           |  |  | 2765 |   | 
        
           |  |  | 2766 |         if ($data->id != $cm->instance) {
 | 
        
           |  |  | 2767 |             // hacker attempt - context does not match the contentid
 | 
        
           |  |  | 2768 |             return false;
 | 
        
           |  |  | 2769 |         }
 | 
        
           |  |  | 2770 |   | 
        
           |  |  | 2771 |         //check if approved
 | 
        
           |  |  | 2772 |         if ($data->approval and !$record->approved and !data_isowner($record) and !has_capability('mod/data:approve', $context)) {
 | 
        
           |  |  | 2773 |             return false;
 | 
        
           |  |  | 2774 |         }
 | 
        
           |  |  | 2775 |   | 
        
           |  |  | 2776 |         // group access
 | 
        
           |  |  | 2777 |         if ($record->groupid) {
 | 
        
           |  |  | 2778 |             $groupmode = groups_get_activity_groupmode($cm, $course);
 | 
        
           |  |  | 2779 |             if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
 | 
        
           |  |  | 2780 |                 if (!groups_is_member($record->groupid)) {
 | 
        
           |  |  | 2781 |                     return false;
 | 
        
           |  |  | 2782 |                 }
 | 
        
           |  |  | 2783 |             }
 | 
        
           |  |  | 2784 |         }
 | 
        
           |  |  | 2785 |   | 
        
           |  |  | 2786 |         $fieldobj = data_get_field($field, $data, $cm);
 | 
        
           |  |  | 2787 |   | 
        
           |  |  | 2788 |         $relativepath = implode('/', $args);
 | 
        
           |  |  | 2789 |         $fullpath = "/$context->id/mod_data/content/$content->id/$relativepath";
 | 
        
           |  |  | 2790 |   | 
        
           |  |  | 2791 |         if (!$fieldobj->file_ok($relativepath)) {
 | 
        
           |  |  | 2792 |             return false;
 | 
        
           |  |  | 2793 |         }
 | 
        
           |  |  | 2794 |   | 
        
           |  |  | 2795 |         $fs = get_file_storage();
 | 
        
           |  |  | 2796 |         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
 | 
        
           |  |  | 2797 |             return false;
 | 
        
           |  |  | 2798 |         }
 | 
        
           |  |  | 2799 |   | 
        
           |  |  | 2800 |         // finally send the file
 | 
        
           |  |  | 2801 |         send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
 | 
        
           |  |  | 2802 |     }
 | 
        
           |  |  | 2803 |   | 
        
           |  |  | 2804 |     return false;
 | 
        
           |  |  | 2805 | }
 | 
        
           |  |  | 2806 |   | 
        
           |  |  | 2807 |   | 
        
           |  |  | 2808 | function data_extend_navigation($navigation, $course, $module, $cm) {
 | 
        
           |  |  | 2809 |     global $CFG, $OUTPUT, $USER, $DB;
 | 
        
           |  |  | 2810 |     require_once($CFG->dirroot . '/mod/data/locallib.php');
 | 
        
           |  |  | 2811 |   | 
        
           |  |  | 2812 |     $rid = optional_param('rid', 0, PARAM_INT);
 | 
        
           |  |  | 2813 |   | 
        
           |  |  | 2814 |     $data = $DB->get_record('data', array('id'=>$cm->instance));
 | 
        
           |  |  | 2815 |     $currentgroup = groups_get_activity_group($cm);
 | 
        
           |  |  | 2816 |     $groupmode = groups_get_activity_groupmode($cm);
 | 
        
           |  |  | 2817 |   | 
        
           |  |  | 2818 |      $numentries = data_numentries($data);
 | 
        
           |  |  | 2819 |     $canmanageentries = has_capability('mod/data:manageentries', context_module::instance($cm->id));
 | 
        
           |  |  | 2820 |   | 
        
           |  |  | 2821 |     if ($data->entriesleft = data_get_entries_left_to_add($data, $numentries, $canmanageentries)) {
 | 
        
           |  |  | 2822 |         $entriesnode = $navigation->add(get_string('entrieslefttoadd', 'data', $data));
 | 
        
           |  |  | 2823 |         $entriesnode->add_class('note');
 | 
        
           |  |  | 2824 |     }
 | 
        
           |  |  | 2825 |   | 
        
           |  |  | 2826 |     $navigation->add(get_string('list', 'data'), new moodle_url('/mod/data/view.php', array('d'=>$cm->instance)));
 | 
        
           |  |  | 2827 |     if (!empty($rid)) {
 | 
        
           |  |  | 2828 |         $navigation->add(get_string('single', 'data'), new moodle_url('/mod/data/view.php', array('d'=>$cm->instance, 'rid'=>$rid)));
 | 
        
           |  |  | 2829 |     } else {
 | 
        
           |  |  | 2830 |         $navigation->add(get_string('single', 'data'), new moodle_url('/mod/data/view.php', array('d'=>$cm->instance, 'mode'=>'single')));
 | 
        
           |  |  | 2831 |     }
 | 
        
           |  |  | 2832 |     $navigation->add(get_string('search', 'data'), new moodle_url('/mod/data/view.php', array('d'=>$cm->instance, 'mode'=>'asearch')));
 | 
        
           |  |  | 2833 | }
 | 
        
           |  |  | 2834 |   | 
        
           |  |  | 2835 | /**
 | 
        
           |  |  | 2836 |  * Adds module specific settings to the settings block
 | 
        
           |  |  | 2837 |  *
 | 
        
           |  |  | 2838 |  * @param settings_navigation $settings The settings navigation object
 | 
        
           |  |  | 2839 |  * @param navigation_node $datanode The node to add module settings to
 | 
        
           |  |  | 2840 |  */
 | 
        
           |  |  | 2841 | function data_extend_settings_navigation(settings_navigation $settings, navigation_node $datanode) {
 | 
        
           |  |  | 2842 |     global $DB, $CFG, $USER;
 | 
        
           |  |  | 2843 |   | 
        
           |  |  | 2844 |     $data = $DB->get_record('data', array("id" => $settings->get_page()->cm->instance));
 | 
        
           |  |  | 2845 |   | 
        
           |  |  | 2846 |     $currentgroup = groups_get_activity_group($settings->get_page()->cm);
 | 
        
           |  |  | 2847 |     $groupmode = groups_get_activity_groupmode($settings->get_page()->cm);
 | 
        
           |  |  | 2848 |   | 
        
           |  |  | 2849 |     // Took out participation list here!
 | 
        
           |  |  | 2850 |     if (data_user_can_add_entry($data, $currentgroup, $groupmode, $settings->get_page()->cm->context)) {
 | 
        
           |  |  | 2851 |         if (empty($editentry)) { //TODO: undefined
 | 
        
           |  |  | 2852 |             $addstring = get_string('add', 'data');
 | 
        
           |  |  | 2853 |         } else {
 | 
        
           |  |  | 2854 |             $addstring = get_string('editentry', 'data');
 | 
        
           |  |  | 2855 |         }
 | 
        
           |  |  | 2856 |         $addentrynode = $datanode->add($addstring,
 | 
        
           |  |  | 2857 |             new moodle_url('/mod/data/edit.php', array('d' => $settings->get_page()->cm->instance)));
 | 
        
           |  |  | 2858 |         $addentrynode->set_show_in_secondary_navigation(false);
 | 
        
           |  |  | 2859 |     }
 | 
        
           |  |  | 2860 |   | 
        
           |  |  | 2861 |     if (has_capability(DATA_CAP_EXPORT, $settings->get_page()->cm->context)) {
 | 
        
           |  |  | 2862 |         // The capability required to Export database records is centrally defined in 'lib.php'
 | 
        
           |  |  | 2863 |         // and should be weaker than those required to edit Templates, Fields and Presets.
 | 
        
           |  |  | 2864 |         $exportentriesnode = $datanode->add(get_string('exportentries', 'data'),
 | 
        
           |  |  | 2865 |             new moodle_url('/mod/data/export.php', array('d' => $data->id)));
 | 
        
           |  |  | 2866 |         $exportentriesnode->set_show_in_secondary_navigation(false);
 | 
        
           |  |  | 2867 |     }
 | 
        
           |  |  | 2868 |     if (has_capability('mod/data:manageentries', $settings->get_page()->cm->context)) {
 | 
        
           |  |  | 2869 |         $importentriesnode = $datanode->add(get_string('importentries', 'data'),
 | 
        
           |  |  | 2870 |             new moodle_url('/mod/data/import.php', array('d' => $data->id)));
 | 
        
           |  |  | 2871 |         $importentriesnode->set_show_in_secondary_navigation(false);
 | 
        
           |  |  | 2872 |     }
 | 
        
           |  |  | 2873 |   | 
        
           |  |  | 2874 |     if (has_capability('mod/data:managetemplates', $settings->get_page()->cm->context)) {
 | 
        
           |  |  | 2875 |         $currenttab = '';
 | 
        
           |  |  | 2876 |         if ($currenttab == 'list') {
 | 
        
           |  |  | 2877 |             $defaultemplate = 'listtemplate';
 | 
        
           |  |  | 2878 |         } else if ($currenttab == 'add') {
 | 
        
           |  |  | 2879 |             $defaultemplate = 'addtemplate';
 | 
        
           |  |  | 2880 |         } else if ($currenttab == 'asearch') {
 | 
        
           |  |  | 2881 |             $defaultemplate = 'asearchtemplate';
 | 
        
           |  |  | 2882 |         } else {
 | 
        
           |  |  | 2883 |             $defaultemplate = 'singletemplate';
 | 
        
           |  |  | 2884 |         }
 | 
        
           |  |  | 2885 |   | 
        
           |  |  | 2886 |         $datanode->add(get_string('presets', 'data'), new moodle_url('/mod/data/preset.php', array('d' => $data->id)));
 | 
        
           |  |  | 2887 |         $datanode->add(get_string('fields', 'data'),
 | 
        
           |  |  | 2888 |             new moodle_url('/mod/data/field.php', array('d' => $data->id)));
 | 
        
           |  |  | 2889 |         $datanode->add(get_string('templates', 'data'),
 | 
        
           |  |  | 2890 |             new moodle_url('/mod/data/templates.php', array('d' => $data->id)));
 | 
        
           |  |  | 2891 |     }
 | 
        
           |  |  | 2892 |   | 
        
           |  |  | 2893 |     if (!empty($CFG->enablerssfeeds) && !empty($CFG->data_enablerssfeeds) && $data->rssarticles > 0) {
 | 
        
           |  |  | 2894 |         require_once("$CFG->libdir/rsslib.php");
 | 
        
           |  |  | 2895 |   | 
        
           |  |  | 2896 |         $string = get_string('rsstype', 'data');
 | 
        
           |  |  | 2897 |   | 
        
           |  |  | 2898 |         $url = new moodle_url(rss_get_url($settings->get_page()->cm->context->id, $USER->id, 'mod_data', $data->id));
 | 
        
           |  |  | 2899 |         $datanode->add($string, $url, settings_navigation::TYPE_SETTING, null, null, new pix_icon('i/rss', ''));
 | 
        
           |  |  | 2900 |     }
 | 
        
           |  |  | 2901 | }
 | 
        
           |  |  | 2902 |   | 
        
           |  |  | 2903 | /**
 | 
        
           |  |  | 2904 |  * Running addtional permission check on plugin, for example, plugins
 | 
        
           |  |  | 2905 |  * may have switch to turn on/off comments option, this callback will
 | 
        
           |  |  | 2906 |  * affect UI display, not like pluginname_comment_validate only throw
 | 
        
           |  |  | 2907 |  * exceptions.
 | 
        
           |  |  | 2908 |  * Capability check has been done in comment->check_permissions(), we
 | 
        
           |  |  | 2909 |  * don't need to do it again here.
 | 
        
           |  |  | 2910 |  *
 | 
        
           |  |  | 2911 |  * @package  mod_data
 | 
        
           |  |  | 2912 |  * @category comment
 | 
        
           |  |  | 2913 |  *
 | 
        
           |  |  | 2914 |  * @param stdClass $comment_param {
 | 
        
           |  |  | 2915 |  *              context  => context the context object
 | 
        
           |  |  | 2916 |  *              courseid => int course id
 | 
        
           |  |  | 2917 |  *              cm       => stdClass course module object
 | 
        
           |  |  | 2918 |  *              commentarea => string comment area
 | 
        
           |  |  | 2919 |  *              itemid      => int itemid
 | 
        
           |  |  | 2920 |  * }
 | 
        
           |  |  | 2921 |  * @return array
 | 
        
           |  |  | 2922 |  */
 | 
        
           |  |  | 2923 | function data_comment_permissions($comment_param) {
 | 
        
           |  |  | 2924 |     global $CFG, $DB;
 | 
        
           |  |  | 2925 |     if (!$record = $DB->get_record('data_records', array('id'=>$comment_param->itemid))) {
 | 
        
           |  |  | 2926 |         throw new comment_exception('invalidcommentitemid');
 | 
        
           |  |  | 2927 |     }
 | 
        
           |  |  | 2928 |     if (!$data = $DB->get_record('data', array('id'=>$record->dataid))) {
 | 
        
           |  |  | 2929 |         throw new comment_exception('invalidid', 'data');
 | 
        
           |  |  | 2930 |     }
 | 
        
           |  |  | 2931 |     if ($data->comments) {
 | 
        
           |  |  | 2932 |         return array('post'=>true, 'view'=>true);
 | 
        
           |  |  | 2933 |     } else {
 | 
        
           |  |  | 2934 |         return array('post'=>false, 'view'=>false);
 | 
        
           |  |  | 2935 |     }
 | 
        
           |  |  | 2936 | }
 | 
        
           |  |  | 2937 |   | 
        
           |  |  | 2938 | /**
 | 
        
           |  |  | 2939 |  * Validate comment parameter before perform other comments actions
 | 
        
           |  |  | 2940 |  *
 | 
        
           |  |  | 2941 |  * @package  mod_data
 | 
        
           |  |  | 2942 |  * @category comment
 | 
        
           |  |  | 2943 |  *
 | 
        
           |  |  | 2944 |  * @param stdClass $comment_param {
 | 
        
           |  |  | 2945 |  *              context  => context the context object
 | 
        
           |  |  | 2946 |  *              courseid => int course id
 | 
        
           |  |  | 2947 |  *              cm       => stdClass course module object
 | 
        
           |  |  | 2948 |  *              commentarea => string comment area
 | 
        
           |  |  | 2949 |  *              itemid      => int itemid
 | 
        
           |  |  | 2950 |  * }
 | 
        
           |  |  | 2951 |  * @return boolean
 | 
        
           |  |  | 2952 |  */
 | 
        
           |  |  | 2953 | function data_comment_validate($comment_param) {
 | 
        
           |  |  | 2954 |     global $DB;
 | 
        
           |  |  | 2955 |     // validate comment area
 | 
        
           |  |  | 2956 |     if ($comment_param->commentarea != 'database_entry') {
 | 
        
           |  |  | 2957 |         throw new comment_exception('invalidcommentarea');
 | 
        
           |  |  | 2958 |     }
 | 
        
           |  |  | 2959 |     // validate itemid
 | 
        
           |  |  | 2960 |     if (!$record = $DB->get_record('data_records', array('id'=>$comment_param->itemid))) {
 | 
        
           |  |  | 2961 |         throw new comment_exception('invalidcommentitemid');
 | 
        
           |  |  | 2962 |     }
 | 
        
           |  |  | 2963 |     if (!$data = $DB->get_record('data', array('id'=>$record->dataid))) {
 | 
        
           |  |  | 2964 |         throw new comment_exception('invalidid', 'data');
 | 
        
           |  |  | 2965 |     }
 | 
        
           |  |  | 2966 |     if (!$course = $DB->get_record('course', array('id'=>$data->course))) {
 | 
        
           |  |  | 2967 |         throw new comment_exception('coursemisconf');
 | 
        
           |  |  | 2968 |     }
 | 
        
           |  |  | 2969 |     if (!$cm = get_coursemodule_from_instance('data', $data->id, $course->id)) {
 | 
        
           |  |  | 2970 |         throw new comment_exception('invalidcoursemodule');
 | 
        
           |  |  | 2971 |     }
 | 
        
           |  |  | 2972 |     if (!$data->comments) {
 | 
        
           |  |  | 2973 |         throw new comment_exception('commentsoff', 'data');
 | 
        
           |  |  | 2974 |     }
 | 
        
           |  |  | 2975 |     $context = context_module::instance($cm->id);
 | 
        
           |  |  | 2976 |   | 
        
           |  |  | 2977 |     //check if approved
 | 
        
           |  |  | 2978 |     if ($data->approval and !$record->approved and !data_isowner($record) and !has_capability('mod/data:approve', $context)) {
 | 
        
           |  |  | 2979 |         throw new comment_exception('notapprovederror', 'data');
 | 
        
           |  |  | 2980 |     }
 | 
        
           |  |  | 2981 |   | 
        
           |  |  | 2982 |     // group access
 | 
        
           |  |  | 2983 |     if ($record->groupid) {
 | 
        
           |  |  | 2984 |         $groupmode = groups_get_activity_groupmode($cm, $course);
 | 
        
           |  |  | 2985 |         if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
 | 
        
           |  |  | 2986 |             if (!groups_is_member($record->groupid)) {
 | 
        
           |  |  | 2987 |                 throw new comment_exception('notmemberofgroup');
 | 
        
           |  |  | 2988 |             }
 | 
        
           |  |  | 2989 |         }
 | 
        
           |  |  | 2990 |     }
 | 
        
           |  |  | 2991 |     // validate context id
 | 
        
           |  |  | 2992 |     if ($context->id != $comment_param->context->id) {
 | 
        
           |  |  | 2993 |         throw new comment_exception('invalidcontext');
 | 
        
           |  |  | 2994 |     }
 | 
        
           |  |  | 2995 |     // validation for comment deletion
 | 
        
           |  |  | 2996 |     if (!empty($comment_param->commentid)) {
 | 
        
           |  |  | 2997 |         if ($comment = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
 | 
        
           |  |  | 2998 |             if ($comment->commentarea != 'database_entry') {
 | 
        
           |  |  | 2999 |                 throw new comment_exception('invalidcommentarea');
 | 
        
           |  |  | 3000 |             }
 | 
        
           |  |  | 3001 |             if ($comment->contextid != $comment_param->context->id) {
 | 
        
           |  |  | 3002 |                 throw new comment_exception('invalidcontext');
 | 
        
           |  |  | 3003 |             }
 | 
        
           |  |  | 3004 |             if ($comment->itemid != $comment_param->itemid) {
 | 
        
           |  |  | 3005 |                 throw new comment_exception('invalidcommentitemid');
 | 
        
           |  |  | 3006 |             }
 | 
        
           |  |  | 3007 |         } else {
 | 
        
           |  |  | 3008 |             throw new comment_exception('invalidcommentid');
 | 
        
           |  |  | 3009 |         }
 | 
        
           |  |  | 3010 |     }
 | 
        
           |  |  | 3011 |     return true;
 | 
        
           |  |  | 3012 | }
 | 
        
           |  |  | 3013 |   | 
        
           |  |  | 3014 | /**
 | 
        
           |  |  | 3015 |  * Return a list of page types
 | 
        
           |  |  | 3016 |  * @param string $pagetype current page type
 | 
        
           |  |  | 3017 |  * @param stdClass $parentcontext Block's parent context
 | 
        
           |  |  | 3018 |  * @param stdClass $currentcontext Current context of block
 | 
        
           |  |  | 3019 |  */
 | 
        
           |  |  | 3020 | function data_page_type_list($pagetype, $parentcontext, $currentcontext) {
 | 
        
           |  |  | 3021 |     $module_pagetype = array('mod-data-*'=>get_string('page-mod-data-x', 'data'));
 | 
        
           |  |  | 3022 |     return $module_pagetype;
 | 
        
           |  |  | 3023 | }
 | 
        
           |  |  | 3024 |   | 
        
           |  |  | 3025 | /**
 | 
        
           |  |  | 3026 |  * Get all of the record ids from a database activity.
 | 
        
           |  |  | 3027 |  *
 | 
        
           |  |  | 3028 |  * @param int    $dataid      The dataid of the database module.
 | 
        
           |  |  | 3029 |  * @param object $selectdata  Contains an additional sql statement for the
 | 
        
           |  |  | 3030 |  *                            where clause for group and approval fields.
 | 
        
           |  |  | 3031 |  * @param array  $params      Parameters that coincide with the sql statement.
 | 
        
           |  |  | 3032 |  * @return array $idarray     An array of record ids
 | 
        
           |  |  | 3033 |  */
 | 
        
           |  |  | 3034 | function data_get_all_recordids($dataid, $selectdata = '', $params = null) {
 | 
        
           |  |  | 3035 |     global $DB;
 | 
        
           |  |  | 3036 |     $initsql = 'SELECT r.id
 | 
        
           |  |  | 3037 |                   FROM {data_records} r
 | 
        
           |  |  | 3038 |                  WHERE r.dataid = :dataid';
 | 
        
           |  |  | 3039 |     if ($selectdata != '') {
 | 
        
           |  |  | 3040 |         $initsql .= $selectdata;
 | 
        
           |  |  | 3041 |         $params = array_merge(array('dataid' => $dataid), $params);
 | 
        
           |  |  | 3042 |     } else {
 | 
        
           |  |  | 3043 |         $params = array('dataid' => $dataid);
 | 
        
           |  |  | 3044 |     }
 | 
        
           |  |  | 3045 |     $initsql .= ' GROUP BY r.id';
 | 
        
           |  |  | 3046 |     $initrecord = $DB->get_recordset_sql($initsql, $params);
 | 
        
           |  |  | 3047 |     $idarray = array();
 | 
        
           |  |  | 3048 |     foreach ($initrecord as $data) {
 | 
        
           |  |  | 3049 |         $idarray[] = $data->id;
 | 
        
           |  |  | 3050 |     }
 | 
        
           |  |  | 3051 |     // Close the record set and free up resources.
 | 
        
           |  |  | 3052 |     $initrecord->close();
 | 
        
           |  |  | 3053 |     return $idarray;
 | 
        
           |  |  | 3054 | }
 | 
        
           |  |  | 3055 |   | 
        
           |  |  | 3056 | /**
 | 
        
           |  |  | 3057 |  * Get the ids of all the records that match that advanced search criteria
 | 
        
           |  |  | 3058 |  * This goes and loops through each criterion one at a time until it either
 | 
        
           |  |  | 3059 |  * runs out of records or returns a subset of records.
 | 
        
           |  |  | 3060 |  *
 | 
        
           |  |  | 3061 |  * @param array $recordids    An array of record ids.
 | 
        
           |  |  | 3062 |  * @param array $searcharray  Contains information for the advanced search criteria
 | 
        
           |  |  | 3063 |  * @param int $dataid         The data id of the database.
 | 
        
           |  |  | 3064 |  * @return array $recordids   An array of record ids.
 | 
        
           |  |  | 3065 |  */
 | 
        
           |  |  | 3066 | function data_get_advance_search_ids($recordids, $searcharray, $dataid) {
 | 
        
           |  |  | 3067 |     // Check to see if we have any record IDs.
 | 
        
           |  |  | 3068 |     if (empty($recordids)) {
 | 
        
           |  |  | 3069 |         // Send back an empty search.
 | 
        
           |  |  | 3070 |         return array();
 | 
        
           |  |  | 3071 |     }
 | 
        
           |  |  | 3072 |     $searchcriteria = array_keys($searcharray);
 | 
        
           |  |  | 3073 |     // Loop through and reduce the IDs one search criteria at a time.
 | 
        
           |  |  | 3074 |     foreach ($searchcriteria as $key) {
 | 
        
           |  |  | 3075 |         $recordids = data_get_recordids($key, $searcharray, $dataid, $recordids);
 | 
        
           |  |  | 3076 |         // If we don't have anymore IDs then stop.
 | 
        
           |  |  | 3077 |         if (!$recordids) {
 | 
        
           |  |  | 3078 |             break;
 | 
        
           |  |  | 3079 |         }
 | 
        
           |  |  | 3080 |     }
 | 
        
           |  |  | 3081 |     return $recordids;
 | 
        
           |  |  | 3082 | }
 | 
        
           |  |  | 3083 |   | 
        
           |  |  | 3084 | /**
 | 
        
           |  |  | 3085 |  * Gets the record IDs given the search criteria
 | 
        
           |  |  | 3086 |  *
 | 
        
           |  |  | 3087 |  * @param string $alias       Record alias.
 | 
        
           |  |  | 3088 |  * @param array $searcharray  Criteria for the search.
 | 
        
           |  |  | 3089 |  * @param int $dataid         Data ID for the database
 | 
        
           |  |  | 3090 |  * @param array $recordids    An array of record IDs.
 | 
        
           |  |  | 3091 |  * @return array $nestarray   An arry of record IDs
 | 
        
           |  |  | 3092 |  */
 | 
        
           |  |  | 3093 | function data_get_recordids($alias, $searcharray, $dataid, $recordids) {
 | 
        
           |  |  | 3094 |     global $DB;
 | 
        
           |  |  | 3095 |     $searchcriteria = $alias;   // Keep the criteria.
 | 
        
           |  |  | 3096 |     $nestsearch = $searcharray[$alias];
 | 
        
           |  |  | 3097 |     // searching for content outside of mdl_data_content
 | 
        
           |  |  | 3098 |     if ($alias < 0) {
 | 
        
           |  |  | 3099 |         $alias = '';
 | 
        
           |  |  | 3100 |     }
 | 
        
           |  |  | 3101 |     list($insql, $params) = $DB->get_in_or_equal($recordids, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 3102 |     $nestselect = 'SELECT c' . $alias . '.recordid
 | 
        
           |  |  | 3103 |                      FROM {data_content} c' . $alias . '
 | 
        
           |  |  | 3104 |                INNER JOIN {data_fields} f
 | 
        
           |  |  | 3105 |                        ON f.id = c' . $alias . '.fieldid
 | 
        
           |  |  | 3106 |                INNER JOIN {data_records} r
 | 
        
           |  |  | 3107 |                        ON r.id = c' . $alias . '.recordid
 | 
        
           |  |  | 3108 |                INNER JOIN {user} u
 | 
        
           |  |  | 3109 |                        ON u.id = r.userid ';
 | 
        
           |  |  | 3110 |     $nestwhere = 'WHERE r.dataid = :dataid
 | 
        
           |  |  | 3111 |                     AND c' . $alias .'.recordid ' . $insql . '
 | 
        
           |  |  | 3112 |                     AND ';
 | 
        
           |  |  | 3113 |   | 
        
           |  |  | 3114 |     $params['dataid'] = $dataid;
 | 
        
           |  |  | 3115 |     if (count($nestsearch->params) != 0) {
 | 
        
           |  |  | 3116 |         $params = array_merge($params, $nestsearch->params);
 | 
        
           |  |  | 3117 |         $nestsql = $nestselect . $nestwhere . $nestsearch->sql;
 | 
        
           |  |  | 3118 |     } else if ($searchcriteria == DATA_TIMEMODIFIED) {
 | 
        
           |  |  | 3119 |         $nestsql = $nestselect . $nestwhere . $nestsearch->field . ' >= :timemodified GROUP BY c' . $alias . '.recordid';
 | 
        
           |  |  | 3120 |         $params['timemodified'] = $nestsearch->data;
 | 
        
           |  |  | 3121 |     } else if ($searchcriteria == DATA_TAGS) {
 | 
        
           |  |  | 3122 |         if (empty($nestsearch->rawtagnames)) {
 | 
        
           |  |  | 3123 |             return [];
 | 
        
           |  |  | 3124 |         }
 | 
        
           |  |  | 3125 |         $i = 0;
 | 
        
           |  |  | 3126 |         $tagwhere = [];
 | 
        
           |  |  | 3127 |         $tagselect = '';
 | 
        
           |  |  | 3128 |         foreach ($nestsearch->rawtagnames as $tagrawname) {
 | 
        
           |  |  | 3129 |             $tagselect .= " INNER JOIN {tag_instance} ti_$i
 | 
        
           |  |  | 3130 |                                     ON ti_$i.component = 'mod_data'
 | 
        
           |  |  | 3131 |                                    AND ti_$i.itemtype = 'data_records'
 | 
        
           |  |  | 3132 |                                    AND ti_$i.itemid = r.id
 | 
        
           |  |  | 3133 |                             INNER JOIN {tag} t_$i
 | 
        
           |  |  | 3134 |                                     ON ti_$i.tagid = t_$i.id ";
 | 
        
           |  |  | 3135 |             $tagwhere[] = " t_$i.rawname = :trawname_$i ";
 | 
        
           |  |  | 3136 |             $params["trawname_$i"] = $tagrawname;
 | 
        
           |  |  | 3137 |             $i++;
 | 
        
           |  |  | 3138 |         }
 | 
        
           |  |  | 3139 |         $nestsql = $nestselect . $tagselect . $nestwhere . implode(' AND ', $tagwhere);
 | 
        
           |  |  | 3140 |     } else {    // First name or last name.
 | 
        
           |  |  | 3141 |         $thing = $DB->sql_like($nestsearch->field, ':search1', false);
 | 
        
           |  |  | 3142 |         $nestsql = $nestselect . $nestwhere . $thing . ' GROUP BY c' . $alias . '.recordid';
 | 
        
           |  |  | 3143 |         $params['search1'] = "%$nestsearch->data%";
 | 
        
           |  |  | 3144 |     }
 | 
        
           |  |  | 3145 |     $nestrecords = $DB->get_recordset_sql($nestsql, $params);
 | 
        
           |  |  | 3146 |     $nestarray = array();
 | 
        
           |  |  | 3147 |     foreach ($nestrecords as $data) {
 | 
        
           |  |  | 3148 |         $nestarray[] = $data->recordid;
 | 
        
           |  |  | 3149 |     }
 | 
        
           |  |  | 3150 |     // Close the record set and free up resources.
 | 
        
           |  |  | 3151 |     $nestrecords->close();
 | 
        
           |  |  | 3152 |     return $nestarray;
 | 
        
           |  |  | 3153 | }
 | 
        
           |  |  | 3154 |   | 
        
           |  |  | 3155 | /**
 | 
        
           |  |  | 3156 |  * Returns an array with an sql string for advanced searches and the parameters that go with them.
 | 
        
           |  |  | 3157 |  *
 | 
        
           |  |  | 3158 |  * @param int $sort            DATA_*
 | 
        
           |  |  | 3159 |  * @param stdClass $data       Data module object
 | 
        
           |  |  | 3160 |  * @param array $recordids     An array of record IDs.
 | 
        
           |  |  | 3161 |  * @param string $selectdata   Information for the where and select part of the sql statement.
 | 
        
           |  |  | 3162 |  * @param string $sortorder    Additional sort parameters
 | 
        
           |  |  | 3163 |  * @return array sqlselect     sqlselect['sql'] has the sql string, sqlselect['params'] contains an array of parameters.
 | 
        
           |  |  | 3164 |  */
 | 
        
           |  |  | 3165 | function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $sortorder) {
 | 
        
           |  |  | 3166 |     global $DB;
 | 
        
           |  |  | 3167 |   | 
        
           |  |  | 3168 |     $userfieldsapi = \core_user\fields::for_userpic()->excluding('id');
 | 
        
           |  |  | 3169 |     $namefields = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
 | 
        
           |  |  | 3170 |   | 
        
           |  |  | 3171 |     if ($sort == 0) {
 | 
        
           |  |  | 3172 |         $nestselectsql = 'SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . '
 | 
        
           |  |  | 3173 |                         FROM {data_content} c,
 | 
        
           |  |  | 3174 |                              {data_records} r,
 | 
        
           |  |  | 3175 |                              {user} u ';
 | 
        
           |  |  | 3176 |         $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' . $namefields;
 | 
        
           |  |  | 3177 |     } else {
 | 
        
           |  |  | 3178 |         // Sorting through 'Other' criteria
 | 
        
           |  |  | 3179 |         if ($sort <= 0) {
 | 
        
           |  |  | 3180 |             switch ($sort) {
 | 
        
           |  |  | 3181 |                 case DATA_LASTNAME:
 | 
        
           |  |  | 3182 |                     $sortcontentfull = "u.lastname";
 | 
        
           |  |  | 3183 |                     break;
 | 
        
           |  |  | 3184 |                 case DATA_FIRSTNAME:
 | 
        
           |  |  | 3185 |                     $sortcontentfull = "u.firstname";
 | 
        
           |  |  | 3186 |                     break;
 | 
        
           |  |  | 3187 |                 case DATA_APPROVED:
 | 
        
           |  |  | 3188 |                     $sortcontentfull = "r.approved";
 | 
        
           |  |  | 3189 |                     break;
 | 
        
           |  |  | 3190 |                 case DATA_TIMEMODIFIED:
 | 
        
           |  |  | 3191 |                     $sortcontentfull = "r.timemodified";
 | 
        
           |  |  | 3192 |                     break;
 | 
        
           |  |  | 3193 |                 case DATA_TIMEADDED:
 | 
        
           |  |  | 3194 |                 default:
 | 
        
           |  |  | 3195 |                     $sortcontentfull = "r.timecreated";
 | 
        
           |  |  | 3196 |             }
 | 
        
           |  |  | 3197 |         } else {
 | 
        
           |  |  | 3198 |             $sortfield = data_get_field_from_id($sort, $data);
 | 
        
           |  |  | 3199 |             $sortcontent = $DB->sql_compare_text('c.' . $sortfield->get_sort_field());
 | 
        
           |  |  | 3200 |             $sortcontentfull = $sortfield->get_sort_sql($sortcontent);
 | 
        
           |  |  | 3201 |         }
 | 
        
           |  |  | 3202 |   | 
        
           |  |  | 3203 |         $nestselectsql = 'SELECT r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . ',
 | 
        
           |  |  | 3204 |                                  ' . $sortcontentfull . '
 | 
        
           |  |  | 3205 |                               AS sortorder
 | 
        
           |  |  | 3206 |                             FROM {data_content} c,
 | 
        
           |  |  | 3207 |                                  {data_records} r,
 | 
        
           |  |  | 3208 |                                  {user} u ';
 | 
        
           |  |  | 3209 |         $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, ' . $namefields . ', ' .$sortcontentfull;
 | 
        
           |  |  | 3210 |     }
 | 
        
           |  |  | 3211 |   | 
        
           |  |  | 3212 |     // Default to a standard Where statement if $selectdata is empty.
 | 
        
           |  |  | 3213 |     if ($selectdata == '') {
 | 
        
           |  |  | 3214 |         $selectdata = 'WHERE c.recordid = r.id
 | 
        
           |  |  | 3215 |                          AND r.dataid = :dataid
 | 
        
           |  |  | 3216 |                          AND r.userid = u.id ';
 | 
        
           |  |  | 3217 |     }
 | 
        
           |  |  | 3218 |   | 
        
           |  |  | 3219 |     // Find the field we are sorting on
 | 
        
           |  |  | 3220 |     if ($sort > 0 or data_get_field_from_id($sort, $data)) {
 | 
        
           |  |  | 3221 |         $selectdata .= ' AND c.fieldid = :sort AND s.recordid = r.id';
 | 
        
           |  |  | 3222 |         $nestselectsql .= ',{data_content} s ';
 | 
        
           |  |  | 3223 |     }
 | 
        
           |  |  | 3224 |   | 
        
           |  |  | 3225 |     // If there are no record IDs then return an sql statment that will return no rows.
 | 
        
           |  |  | 3226 |     if (count($recordids) != 0) {
 | 
        
           |  |  | 3227 |         list($insql, $inparam) = $DB->get_in_or_equal($recordids, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 3228 |     } else {
 | 
        
           |  |  | 3229 |         list($insql, $inparam) = $DB->get_in_or_equal(array('-1'), SQL_PARAMS_NAMED);
 | 
        
           |  |  | 3230 |     }
 | 
        
           |  |  | 3231 |     $nestfromsql = $selectdata . ' AND c.recordid ' . $insql . $groupsql;
 | 
        
           |  |  | 3232 |     $sqlselect['sql'] = "$nestselectsql $nestfromsql $sortorder";
 | 
        
           |  |  | 3233 |     $sqlselect['params'] = $inparam;
 | 
        
           |  |  | 3234 |     return $sqlselect;
 | 
        
           |  |  | 3235 | }
 | 
        
           |  |  | 3236 |   | 
        
           |  |  | 3237 | /**
 | 
        
           |  |  | 3238 |  * Delete a record entry.
 | 
        
           |  |  | 3239 |  *
 | 
        
           |  |  | 3240 |  * @param int $recordid The ID for the record to be deleted.
 | 
        
           |  |  | 3241 |  * @param object $data The data object for this activity.
 | 
        
           |  |  | 3242 |  * @param int $courseid ID for the current course (for logging).
 | 
        
           |  |  | 3243 |  * @param int $cmid The course module ID.
 | 
        
           |  |  | 3244 |  * @return bool True if the record deleted, false if not.
 | 
        
           |  |  | 3245 |  */
 | 
        
           |  |  | 3246 | function data_delete_record($recordid, $data, $courseid, $cmid) {
 | 
        
           |  |  | 3247 |     global $DB, $CFG;
 | 
        
           |  |  | 3248 |   | 
        
           |  |  | 3249 |     if ($deleterecord = $DB->get_record('data_records', array('id' => $recordid))) {
 | 
        
           |  |  | 3250 |         if ($deleterecord->dataid == $data->id) {
 | 
        
           |  |  | 3251 |             if ($contents = $DB->get_records('data_content', array('recordid' => $deleterecord->id))) {
 | 
        
           |  |  | 3252 |                 foreach ($contents as $content) {
 | 
        
           |  |  | 3253 |                     if ($field = data_get_field_from_id($content->fieldid, $data)) {
 | 
        
           |  |  | 3254 |                         $field->delete_content($content->recordid);
 | 
        
           |  |  | 3255 |                     }
 | 
        
           |  |  | 3256 |                 }
 | 
        
           |  |  | 3257 |                 $DB->delete_records('data_content', array('recordid'=>$deleterecord->id));
 | 
        
           |  |  | 3258 |                 $DB->delete_records('data_records', array('id'=>$deleterecord->id));
 | 
        
           |  |  | 3259 |   | 
        
           |  |  | 3260 |                 // Delete cached RSS feeds.
 | 
        
           |  |  | 3261 |                 if (!empty($CFG->enablerssfeeds)) {
 | 
        
           |  |  | 3262 |                     require_once($CFG->dirroot.'/mod/data/rsslib.php');
 | 
        
           |  |  | 3263 |                     data_rss_delete_file($data);
 | 
        
           |  |  | 3264 |                 }
 | 
        
           |  |  | 3265 |   | 
        
           |  |  | 3266 |                 core_tag_tag::remove_all_item_tags('mod_data', 'data_records', $recordid);
 | 
        
           |  |  | 3267 |   | 
        
           |  |  | 3268 |                 // Trigger an event for deleting this record.
 | 
        
           |  |  | 3269 |                 $event = \mod_data\event\record_deleted::create(array(
 | 
        
           |  |  | 3270 |                     'objectid' => $deleterecord->id,
 | 
        
           |  |  | 3271 |                     'context' => context_module::instance($cmid),
 | 
        
           |  |  | 3272 |                     'courseid' => $courseid,
 | 
        
           |  |  | 3273 |                     'other' => array(
 | 
        
           |  |  | 3274 |                         'dataid' => $deleterecord->dataid
 | 
        
           |  |  | 3275 |                     )
 | 
        
           |  |  | 3276 |                 ));
 | 
        
           |  |  | 3277 |                 $event->add_record_snapshot('data_records', $deleterecord);
 | 
        
           |  |  | 3278 |                 $event->trigger();
 | 
        
           |  |  | 3279 |                 $course = get_course($courseid);
 | 
        
           |  |  | 3280 |                 $cm = get_coursemodule_from_instance('data', $data->id, 0, false, MUST_EXIST);
 | 
        
           |  |  | 3281 |                 data_update_completion_state($data, $course, $cm);
 | 
        
           |  |  | 3282 |   | 
        
           |  |  | 3283 |                 return true;
 | 
        
           |  |  | 3284 |             }
 | 
        
           |  |  | 3285 |         }
 | 
        
           |  |  | 3286 |     }
 | 
        
           |  |  | 3287 |   | 
        
           |  |  | 3288 |     return false;
 | 
        
           |  |  | 3289 | }
 | 
        
           |  |  | 3290 |   | 
        
           |  |  | 3291 | /**
 | 
        
           |  |  | 3292 |  * Check for required fields, and build a list of fields to be updated in a
 | 
        
           |  |  | 3293 |  * submission.
 | 
        
           |  |  | 3294 |  *
 | 
        
           |  |  | 3295 |  * @param $mod stdClass The current recordid - provided as an optimisation.
 | 
        
           |  |  | 3296 |  * @param $fields array The field data
 | 
        
           |  |  | 3297 |  * @param $datarecord stdClass The submitted data.
 | 
        
           |  |  | 3298 |  * @return stdClass containing:
 | 
        
           |  |  | 3299 |  * * string[] generalnotifications Notifications for the form as a whole.
 | 
        
           |  |  | 3300 |  * * string[] fieldnotifications Notifications for a specific field.
 | 
        
           |  |  | 3301 |  * * bool validated Whether the field was validated successfully.
 | 
        
           |  |  | 3302 |  * * data_field_base[] fields The field objects to be update.
 | 
        
           |  |  | 3303 |  */
 | 
        
           |  |  | 3304 | function data_process_submission(stdClass $mod, $fields, stdClass $datarecord) {
 | 
        
           |  |  | 3305 |     $result = new stdClass();
 | 
        
           |  |  | 3306 |   | 
        
           |  |  | 3307 |     // Empty form checking - you can't submit an empty form.
 | 
        
           |  |  | 3308 |     $emptyform = true;
 | 
        
           |  |  | 3309 |     $requiredfieldsfilled = true;
 | 
        
           |  |  | 3310 |     $fieldsvalidated = true;
 | 
        
           |  |  | 3311 |   | 
        
           |  |  | 3312 |     // Store the notifications.
 | 
        
           |  |  | 3313 |     $result->generalnotifications = array();
 | 
        
           |  |  | 3314 |     $result->fieldnotifications = array();
 | 
        
           |  |  | 3315 |   | 
        
           |  |  | 3316 |     // Store the instantiated classes as an optimisation when processing the result.
 | 
        
           |  |  | 3317 |     // This prevents the fields being re-initialised when updating.
 | 
        
           |  |  | 3318 |     $result->fields = array();
 | 
        
           |  |  | 3319 |   | 
        
           |  |  | 3320 |     $submitteddata = array();
 | 
        
           |  |  | 3321 |     foreach ($datarecord as $fieldname => $fieldvalue) {
 | 
        
           |  |  | 3322 |         if (strpos($fieldname, '_')) {
 | 
        
           |  |  | 3323 |             $namearray = explode('_', $fieldname, 3);
 | 
        
           |  |  | 3324 |             $fieldid = $namearray[1];
 | 
        
           |  |  | 3325 |             if (!isset($submitteddata[$fieldid])) {
 | 
        
           |  |  | 3326 |                 $submitteddata[$fieldid] = array();
 | 
        
           |  |  | 3327 |             }
 | 
        
           |  |  | 3328 |             if (count($namearray) === 2) {
 | 
        
           |  |  | 3329 |                 $subfieldid = 0;
 | 
        
           |  |  | 3330 |             } else {
 | 
        
           |  |  | 3331 |                 $subfieldid = $namearray[2];
 | 
        
           |  |  | 3332 |             }
 | 
        
           |  |  | 3333 |   | 
        
           |  |  | 3334 |             $fielddata = new stdClass();
 | 
        
           |  |  | 3335 |             $fielddata->fieldname = $fieldname;
 | 
        
           |  |  | 3336 |             $fielddata->value = $fieldvalue;
 | 
        
           |  |  | 3337 |             $submitteddata[$fieldid][$subfieldid] = $fielddata;
 | 
        
           |  |  | 3338 |         }
 | 
        
           |  |  | 3339 |     }
 | 
        
           |  |  | 3340 |   | 
        
           |  |  | 3341 |     // Check all form fields which have the required are filled.
 | 
        
           |  |  | 3342 |     foreach ($fields as $fieldrecord) {
 | 
        
           |  |  | 3343 |         // Check whether the field has any data.
 | 
        
           |  |  | 3344 |         $fieldhascontent = false;
 | 
        
           |  |  | 3345 |   | 
        
           |  |  | 3346 |         $field = data_get_field($fieldrecord, $mod);
 | 
        
           |  |  | 3347 |         if (isset($submitteddata[$fieldrecord->id])) {
 | 
        
           |  |  | 3348 |             // Field validation check.
 | 
        
           |  |  | 3349 |             if (method_exists($field, 'field_validation')) {
 | 
        
           |  |  | 3350 |                 $errormessage = $field->field_validation($submitteddata[$fieldrecord->id]);
 | 
        
           |  |  | 3351 |                 if ($errormessage) {
 | 
        
           |  |  | 3352 |                     $result->fieldnotifications[$field->field->name][] = $errormessage;
 | 
        
           |  |  | 3353 |                     $fieldsvalidated = false;
 | 
        
           |  |  | 3354 |                 }
 | 
        
           |  |  | 3355 |             }
 | 
        
           |  |  | 3356 |             foreach ($submitteddata[$fieldrecord->id] as $fieldname => $value) {
 | 
        
           |  |  | 3357 |                 if ($field->notemptyfield($value->value, $value->fieldname)) {
 | 
        
           |  |  | 3358 |                     // The field has content and the form is not empty.
 | 
        
           |  |  | 3359 |                     $fieldhascontent = true;
 | 
        
           |  |  | 3360 |                     $emptyform = false;
 | 
        
           |  |  | 3361 |                 }
 | 
        
           |  |  | 3362 |             }
 | 
        
           |  |  | 3363 |         }
 | 
        
           |  |  | 3364 |   | 
        
           |  |  | 3365 |         // If the field is required, add a notification to that effect.
 | 
        
           |  |  | 3366 |         if ($field->field->required && !$fieldhascontent) {
 | 
        
           |  |  | 3367 |             if (!isset($result->fieldnotifications[$field->field->name])) {
 | 
        
           |  |  | 3368 |                 $result->fieldnotifications[$field->field->name] = array();
 | 
        
           |  |  | 3369 |             }
 | 
        
           |  |  | 3370 |             $result->fieldnotifications[$field->field->name][] = get_string('errormustsupplyvalue', 'data');
 | 
        
           |  |  | 3371 |             $requiredfieldsfilled = false;
 | 
        
           |  |  | 3372 |         }
 | 
        
           |  |  | 3373 |   | 
        
           |  |  | 3374 |         // Update the field.
 | 
        
           |  |  | 3375 |         if (isset($submitteddata[$fieldrecord->id])) {
 | 
        
           |  |  | 3376 |             foreach ($submitteddata[$fieldrecord->id] as $value) {
 | 
        
           |  |  | 3377 |                 $result->fields[$value->fieldname] = $field;
 | 
        
           |  |  | 3378 |             }
 | 
        
           |  |  | 3379 |         }
 | 
        
           |  |  | 3380 |     }
 | 
        
           |  |  | 3381 |   | 
        
           |  |  | 3382 |     if ($emptyform) {
 | 
        
           |  |  | 3383 |         // The form is empty.
 | 
        
           |  |  | 3384 |         $result->generalnotifications[] = get_string('emptyaddform', 'data');
 | 
        
           |  |  | 3385 |     }
 | 
        
           |  |  | 3386 |   | 
        
           |  |  | 3387 |     $result->validated = $requiredfieldsfilled && !$emptyform && $fieldsvalidated;
 | 
        
           |  |  | 3388 |   | 
        
           |  |  | 3389 |     return $result;
 | 
        
           |  |  | 3390 | }
 | 
        
           |  |  | 3391 |   | 
        
           |  |  | 3392 | /**
 | 
        
           |  |  | 3393 |  * This standard function will check all instances of this module
 | 
        
           |  |  | 3394 |  * and make sure there are up-to-date events created for each of them.
 | 
        
           |  |  | 3395 |  * If courseid = 0, then every data event in the site is checked, else
 | 
        
           |  |  | 3396 |  * only data events belonging to the course specified are checked.
 | 
        
           |  |  | 3397 |  * This function is used, in its new format, by restore_refresh_events()
 | 
        
           |  |  | 3398 |  *
 | 
        
           |  |  | 3399 |  * @param int $courseid
 | 
        
           |  |  | 3400 |  * @param int|stdClass $instance Data module instance or ID.
 | 
        
           |  |  | 3401 |  * @param int|stdClass $cm Course module object or ID (not used in this module).
 | 
        
           |  |  | 3402 |  * @return bool
 | 
        
           |  |  | 3403 |  */
 | 
        
           |  |  | 3404 | function data_refresh_events($courseid = 0, $instance = null, $cm = null) {
 | 
        
           |  |  | 3405 |     global $DB, $CFG;
 | 
        
           |  |  | 3406 |     require_once($CFG->dirroot.'/mod/data/locallib.php');
 | 
        
           |  |  | 3407 |   | 
        
           |  |  | 3408 |     // If we have instance information then we can just update the one event instead of updating all events.
 | 
        
           |  |  | 3409 |     if (isset($instance)) {
 | 
        
           |  |  | 3410 |         if (!is_object($instance)) {
 | 
        
           |  |  | 3411 |             $instance = $DB->get_record('data', array('id' => $instance), '*', MUST_EXIST);
 | 
        
           |  |  | 3412 |         }
 | 
        
           |  |  | 3413 |         data_set_events($instance);
 | 
        
           |  |  | 3414 |         return true;
 | 
        
           |  |  | 3415 |     }
 | 
        
           |  |  | 3416 |   | 
        
           |  |  | 3417 |     if ($courseid) {
 | 
        
           |  |  | 3418 |         if (! $data = $DB->get_records("data", array("course" => $courseid))) {
 | 
        
           |  |  | 3419 |             return true;
 | 
        
           |  |  | 3420 |         }
 | 
        
           |  |  | 3421 |     } else {
 | 
        
           |  |  | 3422 |         if (! $data = $DB->get_records("data")) {
 | 
        
           |  |  | 3423 |             return true;
 | 
        
           |  |  | 3424 |         }
 | 
        
           |  |  | 3425 |     }
 | 
        
           |  |  | 3426 |   | 
        
           |  |  | 3427 |     foreach ($data as $datum) {
 | 
        
           |  |  | 3428 |         data_set_events($datum);
 | 
        
           |  |  | 3429 |     }
 | 
        
           |  |  | 3430 |     return true;
 | 
        
           |  |  | 3431 | }
 | 
        
           |  |  | 3432 |   | 
        
           |  |  | 3433 | /**
 | 
        
           |  |  | 3434 |  * Fetch the configuration for this database activity.
 | 
        
           |  |  | 3435 |  *
 | 
        
           |  |  | 3436 |  * @param   stdClass    $database   The object returned from the database for this instance
 | 
        
           |  |  | 3437 |  * @param   string      $key        The name of the key to retrieve. If none is supplied, then all configuration is returned
 | 
        
           |  |  | 3438 |  * @param   mixed       $default    The default value to use if no value was found for the specified key
 | 
        
           |  |  | 3439 |  * @return  mixed                   The returned value
 | 
        
           |  |  | 3440 |  */
 | 
        
           |  |  | 3441 | function data_get_config($database, $key = null, $default = null) {
 | 
        
           |  |  | 3442 |     if (!empty($database->config)) {
 | 
        
           |  |  | 3443 |         $config = json_decode($database->config);
 | 
        
           |  |  | 3444 |     } else {
 | 
        
           |  |  | 3445 |         $config = new stdClass();
 | 
        
           |  |  | 3446 |     }
 | 
        
           |  |  | 3447 |   | 
        
           |  |  | 3448 |     if ($key === null) {
 | 
        
           |  |  | 3449 |         return $config;
 | 
        
           |  |  | 3450 |     }
 | 
        
           |  |  | 3451 |   | 
        
           |  |  | 3452 |     if (property_exists($config, $key)) {
 | 
        
           |  |  | 3453 |         return $config->$key;
 | 
        
           |  |  | 3454 |     }
 | 
        
           |  |  | 3455 |     return $default;
 | 
        
           |  |  | 3456 | }
 | 
        
           |  |  | 3457 |   | 
        
           |  |  | 3458 | /**
 | 
        
           |  |  | 3459 |  * Update the configuration for this database activity.
 | 
        
           |  |  | 3460 |  *
 | 
        
           |  |  | 3461 |  * @param   stdClass    $database   The object returned from the database for this instance
 | 
        
           |  |  | 3462 |  * @param   string      $key        The name of the key to set
 | 
        
           |  |  | 3463 |  * @param   mixed       $value      The value to set for the key
 | 
        
           |  |  | 3464 |  */
 | 
        
           |  |  | 3465 | function data_set_config(&$database, $key, $value) {
 | 
        
           |  |  | 3466 |     // Note: We must pass $database by reference because there may be subsequent calls to update_record and these should
 | 
        
           |  |  | 3467 |     // not overwrite the configuration just set.
 | 
        
           |  |  | 3468 |     global $DB;
 | 
        
           |  |  | 3469 |   | 
        
           |  |  | 3470 |     $config = data_get_config($database);
 | 
        
           |  |  | 3471 |   | 
        
           |  |  | 3472 |     if (!isset($config->$key) || $config->$key !== $value) {
 | 
        
           |  |  | 3473 |         $config->$key = $value;
 | 
        
           |  |  | 3474 |         $database->config = json_encode($config);
 | 
        
           |  |  | 3475 |         $DB->set_field('data', 'config', $database->config, ['id' => $database->id]);
 | 
        
           |  |  | 3476 |     }
 | 
        
           |  |  | 3477 | }
 | 
        
           |  |  | 3478 | /**
 | 
        
           |  |  | 3479 |  * Sets the automatic completion state for this database item based on the
 | 
        
           |  |  | 3480 |  * count of on its entries.
 | 
        
           |  |  | 3481 |  * @since Moodle 3.3
 | 
        
           |  |  | 3482 |  * @param object $data The data object for this activity
 | 
        
           |  |  | 3483 |  * @param object $course Course
 | 
        
           |  |  | 3484 |  * @param object $cm course-module
 | 
        
           |  |  | 3485 |  */
 | 
        
           |  |  | 3486 | function data_update_completion_state($data, $course, $cm) {
 | 
        
           |  |  | 3487 |     // If completion option is enabled, evaluate it and return true/false.
 | 
        
           |  |  | 3488 |     $completion = new completion_info($course);
 | 
        
           |  |  | 3489 |     if ($data->completionentries && $completion->is_enabled($cm)) {
 | 
        
           |  |  | 3490 |         $numentries = data_numentries($data);
 | 
        
           |  |  | 3491 |         // Check the number of entries required against the number of entries already made.
 | 
        
           |  |  | 3492 |         if ($numentries >= $data->completionentries) {
 | 
        
           |  |  | 3493 |             $completion->update_state($cm, COMPLETION_COMPLETE);
 | 
        
           |  |  | 3494 |         } else {
 | 
        
           |  |  | 3495 |             $completion->update_state($cm, COMPLETION_INCOMPLETE);
 | 
        
           |  |  | 3496 |         }
 | 
        
           |  |  | 3497 |     }
 | 
        
           |  |  | 3498 | }
 | 
        
           |  |  | 3499 |   | 
        
           | 1441 | ariadna | 3500 |   | 
        
           | 1 | efrain | 3501 | /**
 | 
        
           | 1441 | ariadna | 3502 |  * Get the list of deprecated icons.
 | 
        
           | 1 | efrain | 3503 |  *
 | 
        
           | 1441 | ariadna | 3504 |  * @return array with the deprecated key icons.
 | 
        
           |  |  | 3505 |  * @todo Final deprecation on Moodle 6.0 MDL-83465.
 | 
        
           | 1 | efrain | 3506 |  */
 | 
        
           | 1441 | ariadna | 3507 | function mod_data_get_deprecated_icons() {
 | 
        
           | 1 | efrain | 3508 |     return [
 | 
        
           | 1441 | ariadna | 3509 |         // Deprecated since Moodle 4.6.
 | 
        
           |  |  | 3510 |         // See MDL-82313 for refactoring.
 | 
        
           |  |  | 3511 |         'mod_data:field/checkbox' => 'fa-regular fa-square-check',
 | 
        
           |  |  | 3512 |         'mod_data:field/date' => 'fa-regular fa-calendar',
 | 
        
           |  |  | 3513 |         'mod_data:field/file' => 'fa-regular fa-file',
 | 
        
           |  |  | 3514 |         'mod_data:field/latlong' => 'fa-earth-americas',
 | 
        
           | 1 | efrain | 3515 |         'mod_data:field/menu' => 'fa-bars',
 | 
        
           |  |  | 3516 |         'mod_data:field/multimenu' => 'fa-bars',
 | 
        
           |  |  | 3517 |         'mod_data:field/number' => 'fa-hashtag',
 | 
        
           | 1441 | ariadna | 3518 |         'mod_data:field/picture' => 'fa-regular fa-image',
 | 
        
           |  |  | 3519 |         'mod_data:field/radiobutton' => 'fa-regular fa-circle-dot',
 | 
        
           |  |  | 3520 |         'mod_data:field/text' => 'fa-i-cursor',
 | 
        
           | 1 | efrain | 3521 |         'mod_data:field/textarea' => 'fa-font',
 | 
        
           |  |  | 3522 |         'mod_data:field/url' => 'fa-link',
 | 
        
           |  |  | 3523 |     ];
 | 
        
           |  |  | 3524 | }
 | 
        
           |  |  | 3525 |   | 
        
           |  |  | 3526 | /*
 | 
        
           |  |  | 3527 |  * Check if the module has any update that affects the current user since a given time.
 | 
        
           |  |  | 3528 |  *
 | 
        
           |  |  | 3529 |  * @param  cm_info $cm course module data
 | 
        
           |  |  | 3530 |  * @param  int $from the time to check updates from
 | 
        
           |  |  | 3531 |  * @param  array $filter  if we need to check only specific updates
 | 
        
           |  |  | 3532 |  * @return stdClass an object with the different type of areas indicating if they were updated or not
 | 
        
           |  |  | 3533 |  * @since Moodle 3.2
 | 
        
           |  |  | 3534 |  */
 | 
        
           |  |  | 3535 | function data_check_updates_since(cm_info $cm, $from, $filter = array()) {
 | 
        
           |  |  | 3536 |     global $DB, $CFG;
 | 
        
           |  |  | 3537 |     require_once($CFG->dirroot . '/mod/data/locallib.php');
 | 
        
           |  |  | 3538 |   | 
        
           |  |  | 3539 |     $updates = course_check_module_updates_since($cm, $from, array(), $filter);
 | 
        
           |  |  | 3540 |   | 
        
           |  |  | 3541 |     // Check for new entries.
 | 
        
           |  |  | 3542 |     $updates->entries = (object) array('updated' => false);
 | 
        
           |  |  | 3543 |   | 
        
           |  |  | 3544 |     $data = $DB->get_record('data', array('id' => $cm->instance), '*', MUST_EXIST);
 | 
        
           |  |  | 3545 |     $searcharray = [];
 | 
        
           |  |  | 3546 |     $searcharray[DATA_TIMEMODIFIED] = new stdClass();
 | 
        
           |  |  | 3547 |     $searcharray[DATA_TIMEMODIFIED]->sql     = '';
 | 
        
           |  |  | 3548 |     $searcharray[DATA_TIMEMODIFIED]->params  = array();
 | 
        
           |  |  | 3549 |     $searcharray[DATA_TIMEMODIFIED]->field   = 'r.timemodified';
 | 
        
           |  |  | 3550 |     $searcharray[DATA_TIMEMODIFIED]->data    = $from;
 | 
        
           |  |  | 3551 |   | 
        
           |  |  | 3552 |     $currentgroup = groups_get_activity_group($cm);
 | 
        
           |  |  | 3553 |     // Teachers should retrieve all entries when not in separate groups.
 | 
        
           |  |  | 3554 |     if (has_capability('mod/data:manageentries', $cm->context) && groups_get_activity_groupmode($cm) != SEPARATEGROUPS) {
 | 
        
           |  |  | 3555 |         $currentgroup = 0;
 | 
        
           |  |  | 3556 |     }
 | 
        
           |  |  | 3557 |     list($entries, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
 | 
        
           |  |  | 3558 |         data_search_entries($data, $cm, $cm->context, 'list', $currentgroup, '', null, null, 0, 0, true, $searcharray);
 | 
        
           |  |  | 3559 |   | 
        
           |  |  | 3560 |     if (!empty($entries)) {
 | 
        
           |  |  | 3561 |         $updates->entries->updated = true;
 | 
        
           |  |  | 3562 |         $updates->entries->itemids = array_keys($entries);
 | 
        
           |  |  | 3563 |     }
 | 
        
           |  |  | 3564 |   | 
        
           |  |  | 3565 |     return $updates;
 | 
        
           |  |  | 3566 | }
 | 
        
           |  |  | 3567 |   | 
        
           |  |  | 3568 | /**
 | 
        
           |  |  | 3569 |  * This function receives a calendar event and returns the action associated with it, or null if there is none.
 | 
        
           |  |  | 3570 |  *
 | 
        
           |  |  | 3571 |  * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event
 | 
        
           |  |  | 3572 |  * is not displayed on the block.
 | 
        
           |  |  | 3573 |  *
 | 
        
           |  |  | 3574 |  * @param calendar_event $event
 | 
        
           |  |  | 3575 |  * @param \core_calendar\action_factory $factory
 | 
        
           |  |  | 3576 |  * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
 | 
        
           |  |  | 3577 |  * @return \core_calendar\local\event\entities\action_interface|null
 | 
        
           |  |  | 3578 |  */
 | 
        
           |  |  | 3579 | function mod_data_core_calendar_provide_event_action(calendar_event $event,
 | 
        
           |  |  | 3580 |                                                      \core_calendar\action_factory $factory,
 | 
        
           |  |  | 3581 |                                                      int $userid = 0) {
 | 
        
           |  |  | 3582 |     global $USER;
 | 
        
           |  |  | 3583 |   | 
        
           |  |  | 3584 |     if (!$userid) {
 | 
        
           |  |  | 3585 |         $userid = $USER->id;
 | 
        
           |  |  | 3586 |     }
 | 
        
           |  |  | 3587 |   | 
        
           |  |  | 3588 |     $cm = get_fast_modinfo($event->courseid, $userid)->instances['data'][$event->instance];
 | 
        
           |  |  | 3589 |   | 
        
           |  |  | 3590 |     if (!$cm->uservisible) {
 | 
        
           |  |  | 3591 |         // The module is not visible to the user for any reason.
 | 
        
           |  |  | 3592 |         return null;
 | 
        
           |  |  | 3593 |     }
 | 
        
           |  |  | 3594 |   | 
        
           |  |  | 3595 |     $now = time();
 | 
        
           |  |  | 3596 |   | 
        
           |  |  | 3597 |     if (!empty($cm->customdata['timeavailableto']) && $cm->customdata['timeavailableto'] < $now) {
 | 
        
           |  |  | 3598 |         // The module has closed so the user can no longer submit anything.
 | 
        
           |  |  | 3599 |         return null;
 | 
        
           |  |  | 3600 |     }
 | 
        
           |  |  | 3601 |   | 
        
           |  |  | 3602 |     // The module is actionable if we don't have a start time or the start time is
 | 
        
           |  |  | 3603 |     // in the past.
 | 
        
           |  |  | 3604 |     $actionable = (empty($cm->customdata['timeavailablefrom']) || $cm->customdata['timeavailablefrom'] <= $now);
 | 
        
           |  |  | 3605 |   | 
        
           |  |  | 3606 |     return $factory->create_instance(
 | 
        
           |  |  | 3607 |         get_string('add', 'data'),
 | 
        
           |  |  | 3608 |         new \moodle_url('/mod/data/view.php', array('id' => $cm->id)),
 | 
        
           |  |  | 3609 |         1,
 | 
        
           |  |  | 3610 |         $actionable
 | 
        
           |  |  | 3611 |     );
 | 
        
           |  |  | 3612 | }
 | 
        
           |  |  | 3613 |   | 
        
           |  |  | 3614 | /**
 | 
        
           |  |  | 3615 |  * Add a get_coursemodule_info function in case any database type wants to add 'extra' information
 | 
        
           |  |  | 3616 |  * for the course (see resource).
 | 
        
           |  |  | 3617 |  *
 | 
        
           |  |  | 3618 |  * Given a course_module object, this function returns any "extra" information that may be needed
 | 
        
           |  |  | 3619 |  * when printing this activity in a course listing.  See get_array_of_activities() in course/lib.php.
 | 
        
           |  |  | 3620 |  *
 | 
        
           |  |  | 3621 |  * @param stdClass $coursemodule The coursemodule object (record).
 | 
        
           |  |  | 3622 |  * @return cached_cm_info An object on information that the courses
 | 
        
           |  |  | 3623 |  *                        will know about (most noticeably, an icon).
 | 
        
           |  |  | 3624 |  */
 | 
        
           |  |  | 3625 | function data_get_coursemodule_info($coursemodule) {
 | 
        
           |  |  | 3626 |     global $DB;
 | 
        
           |  |  | 3627 |   | 
        
           |  |  | 3628 |     $dbparams = ['id' => $coursemodule->instance];
 | 
        
           |  |  | 3629 |     $fields = 'id, name, intro, introformat, completionentries, timeavailablefrom, timeavailableto';
 | 
        
           |  |  | 3630 |     if (!$data = $DB->get_record('data', $dbparams, $fields)) {
 | 
        
           |  |  | 3631 |         return false;
 | 
        
           |  |  | 3632 |     }
 | 
        
           |  |  | 3633 |   | 
        
           |  |  | 3634 |     $result = new cached_cm_info();
 | 
        
           |  |  | 3635 |     $result->name = $data->name;
 | 
        
           |  |  | 3636 |   | 
        
           |  |  | 3637 |     if ($coursemodule->showdescription) {
 | 
        
           |  |  | 3638 |         // Convert intro to html. Do not filter cached version, filters run at display time.
 | 
        
           |  |  | 3639 |         $result->content = format_module_intro('data', $data, $coursemodule->id, false);
 | 
        
           |  |  | 3640 |     }
 | 
        
           |  |  | 3641 |   | 
        
           |  |  | 3642 |     // Populate the custom completion rules as key => value pairs, but only if the completion mode is 'automatic'.
 | 
        
           |  |  | 3643 |     if ($coursemodule->completion == COMPLETION_TRACKING_AUTOMATIC) {
 | 
        
           |  |  | 3644 |         $result->customdata['customcompletionrules']['completionentries'] = $data->completionentries;
 | 
        
           |  |  | 3645 |     }
 | 
        
           |  |  | 3646 |     // Other properties that may be used in calendar or on dashboard.
 | 
        
           |  |  | 3647 |     if ($data->timeavailablefrom) {
 | 
        
           |  |  | 3648 |         $result->customdata['timeavailablefrom'] = $data->timeavailablefrom;
 | 
        
           |  |  | 3649 |     }
 | 
        
           |  |  | 3650 |     if ($data->timeavailableto) {
 | 
        
           |  |  | 3651 |         $result->customdata['timeavailableto'] = $data->timeavailableto;
 | 
        
           |  |  | 3652 |     }
 | 
        
           |  |  | 3653 |   | 
        
           |  |  | 3654 |     return $result;
 | 
        
           |  |  | 3655 | }
 | 
        
           |  |  | 3656 |   | 
        
           |  |  | 3657 | /**
 | 
        
           |  |  | 3658 |  * Callback which returns human-readable strings describing the active completion custom rules for the module instance.
 | 
        
           |  |  | 3659 |  *
 | 
        
           |  |  | 3660 |  * @param cm_info|stdClass $cm object with fields ->completion and ->customdata['customcompletionrules']
 | 
        
           |  |  | 3661 |  * @return array $descriptions the array of descriptions for the custom rules.
 | 
        
           |  |  | 3662 |  */
 | 
        
           |  |  | 3663 | function mod_data_get_completion_active_rule_descriptions($cm) {
 | 
        
           |  |  | 3664 |     // Values will be present in cm_info, and we assume these are up to date.
 | 
        
           |  |  | 3665 |     if (empty($cm->customdata['customcompletionrules'])
 | 
        
           |  |  | 3666 |         || $cm->completion != COMPLETION_TRACKING_AUTOMATIC) {
 | 
        
           |  |  | 3667 |         return [];
 | 
        
           |  |  | 3668 |     }
 | 
        
           |  |  | 3669 |   | 
        
           |  |  | 3670 |     $descriptions = [];
 | 
        
           |  |  | 3671 |     foreach ($cm->customdata['customcompletionrules'] as $key => $val) {
 | 
        
           |  |  | 3672 |         switch ($key) {
 | 
        
           |  |  | 3673 |             case 'completionentries':
 | 
        
           |  |  | 3674 |                 if (!empty($val)) {
 | 
        
           |  |  | 3675 |                     $descriptions[] = get_string('completionentriesdesc', 'data', $val);
 | 
        
           |  |  | 3676 |                 }
 | 
        
           |  |  | 3677 |                 break;
 | 
        
           |  |  | 3678 |             default:
 | 
        
           |  |  | 3679 |                 break;
 | 
        
           |  |  | 3680 |         }
 | 
        
           |  |  | 3681 |     }
 | 
        
           |  |  | 3682 |     return $descriptions;
 | 
        
           |  |  | 3683 | }
 | 
        
           |  |  | 3684 |   | 
        
           |  |  | 3685 | /**
 | 
        
           |  |  | 3686 |  * This function calculates the minimum and maximum cutoff values for the timestart of
 | 
        
           |  |  | 3687 |  * the given event.
 | 
        
           |  |  | 3688 |  *
 | 
        
           |  |  | 3689 |  * It will return an array with two values, the first being the minimum cutoff value and
 | 
        
           |  |  | 3690 |  * the second being the maximum cutoff value. Either or both values can be null, which
 | 
        
           |  |  | 3691 |  * indicates there is no minimum or maximum, respectively.
 | 
        
           |  |  | 3692 |  *
 | 
        
           |  |  | 3693 |  * If a cutoff is required then the function must return an array containing the cutoff
 | 
        
           |  |  | 3694 |  * timestamp and error string to display to the user if the cutoff value is violated.
 | 
        
           |  |  | 3695 |  *
 | 
        
           |  |  | 3696 |  * A minimum and maximum cutoff return value will look like:
 | 
        
           |  |  | 3697 |  * [
 | 
        
           |  |  | 3698 |  *     [1505704373, 'The due date must be after the sbumission start date'],
 | 
        
           |  |  | 3699 |  *     [1506741172, 'The due date must be before the cutoff date']
 | 
        
           |  |  | 3700 |  * ]
 | 
        
           |  |  | 3701 |  *
 | 
        
           |  |  | 3702 |  * @param calendar_event $event The calendar event to get the time range for
 | 
        
           |  |  | 3703 |  * @param stdClass $instance The module instance to get the range from
 | 
        
           |  |  | 3704 |  * @return array
 | 
        
           |  |  | 3705 |  */
 | 
        
           |  |  | 3706 | function mod_data_core_calendar_get_valid_event_timestart_range(\calendar_event $event, \stdClass $instance) {
 | 
        
           |  |  | 3707 |     $mindate = null;
 | 
        
           |  |  | 3708 |     $maxdate = null;
 | 
        
           |  |  | 3709 |   | 
        
           |  |  | 3710 |     if ($event->eventtype == DATA_EVENT_TYPE_OPEN) {
 | 
        
           |  |  | 3711 |         // The start time of the open event can't be equal to or after the
 | 
        
           |  |  | 3712 |         // close time of the database activity.
 | 
        
           |  |  | 3713 |         if (!empty($instance->timeavailableto)) {
 | 
        
           |  |  | 3714 |             $maxdate = [
 | 
        
           |  |  | 3715 |                 $instance->timeavailableto,
 | 
        
           |  |  | 3716 |                 get_string('openafterclose', 'data')
 | 
        
           |  |  | 3717 |             ];
 | 
        
           |  |  | 3718 |         }
 | 
        
           |  |  | 3719 |     } else if ($event->eventtype == DATA_EVENT_TYPE_CLOSE) {
 | 
        
           |  |  | 3720 |         // The start time of the close event can't be equal to or earlier than the
 | 
        
           |  |  | 3721 |         // open time of the database activity.
 | 
        
           |  |  | 3722 |         if (!empty($instance->timeavailablefrom)) {
 | 
        
           |  |  | 3723 |             $mindate = [
 | 
        
           |  |  | 3724 |                 $instance->timeavailablefrom,
 | 
        
           |  |  | 3725 |                 get_string('closebeforeopen', 'data')
 | 
        
           |  |  | 3726 |             ];
 | 
        
           |  |  | 3727 |         }
 | 
        
           |  |  | 3728 |     }
 | 
        
           |  |  | 3729 |   | 
        
           |  |  | 3730 |     return [$mindate, $maxdate];
 | 
        
           |  |  | 3731 | }
 | 
        
           |  |  | 3732 |   | 
        
           |  |  | 3733 | /**
 | 
        
           |  |  | 3734 |  * This function will update the data module according to the
 | 
        
           |  |  | 3735 |  * event that has been modified.
 | 
        
           |  |  | 3736 |  *
 | 
        
           |  |  | 3737 |  * It will set the timeopen or timeclose value of the data instance
 | 
        
           |  |  | 3738 |  * according to the type of event provided.
 | 
        
           |  |  | 3739 |  *
 | 
        
           |  |  | 3740 |  * @throws \moodle_exception
 | 
        
           |  |  | 3741 |  * @param \calendar_event $event
 | 
        
           |  |  | 3742 |  * @param stdClass $data The module instance to get the range from
 | 
        
           |  |  | 3743 |  */
 | 
        
           |  |  | 3744 | function mod_data_core_calendar_event_timestart_updated(\calendar_event $event, \stdClass $data) {
 | 
        
           |  |  | 3745 |     global $DB;
 | 
        
           |  |  | 3746 |   | 
        
           |  |  | 3747 |     if (empty($event->instance) || $event->modulename != 'data') {
 | 
        
           |  |  | 3748 |         return;
 | 
        
           |  |  | 3749 |     }
 | 
        
           |  |  | 3750 |   | 
        
           |  |  | 3751 |     if ($event->instance != $data->id) {
 | 
        
           |  |  | 3752 |         return;
 | 
        
           |  |  | 3753 |     }
 | 
        
           |  |  | 3754 |   | 
        
           |  |  | 3755 |     if (!in_array($event->eventtype, [DATA_EVENT_TYPE_OPEN, DATA_EVENT_TYPE_CLOSE])) {
 | 
        
           |  |  | 3756 |         return;
 | 
        
           |  |  | 3757 |     }
 | 
        
           |  |  | 3758 |   | 
        
           |  |  | 3759 |     $courseid = $event->courseid;
 | 
        
           |  |  | 3760 |     $modulename = $event->modulename;
 | 
        
           |  |  | 3761 |     $instanceid = $event->instance;
 | 
        
           |  |  | 3762 |     $modified = false;
 | 
        
           |  |  | 3763 |   | 
        
           |  |  | 3764 |     $coursemodule = get_fast_modinfo($courseid)->instances[$modulename][$instanceid];
 | 
        
           |  |  | 3765 |     $context = context_module::instance($coursemodule->id);
 | 
        
           |  |  | 3766 |   | 
        
           |  |  | 3767 |     // The user does not have the capability to modify this activity.
 | 
        
           |  |  | 3768 |     if (!has_capability('moodle/course:manageactivities', $context)) {
 | 
        
           |  |  | 3769 |         return;
 | 
        
           |  |  | 3770 |     }
 | 
        
           |  |  | 3771 |   | 
        
           |  |  | 3772 |     if ($event->eventtype == DATA_EVENT_TYPE_OPEN) {
 | 
        
           |  |  | 3773 |         // If the event is for the data activity opening then we should
 | 
        
           |  |  | 3774 |         // set the start time of the data activity to be the new start
 | 
        
           |  |  | 3775 |         // time of the event.
 | 
        
           |  |  | 3776 |         if ($data->timeavailablefrom != $event->timestart) {
 | 
        
           |  |  | 3777 |             $data->timeavailablefrom = $event->timestart;
 | 
        
           |  |  | 3778 |             $data->timemodified = time();
 | 
        
           |  |  | 3779 |             $modified = true;
 | 
        
           |  |  | 3780 |         }
 | 
        
           |  |  | 3781 |     } else if ($event->eventtype == DATA_EVENT_TYPE_CLOSE) {
 | 
        
           |  |  | 3782 |         // If the event is for the data activity closing then we should
 | 
        
           |  |  | 3783 |         // set the end time of the data activity to be the new start
 | 
        
           |  |  | 3784 |         // time of the event.
 | 
        
           |  |  | 3785 |         if ($data->timeavailableto != $event->timestart) {
 | 
        
           |  |  | 3786 |             $data->timeavailableto = $event->timestart;
 | 
        
           |  |  | 3787 |             $modified = true;
 | 
        
           |  |  | 3788 |         }
 | 
        
           |  |  | 3789 |     }
 | 
        
           |  |  | 3790 |   | 
        
           |  |  | 3791 |     if ($modified) {
 | 
        
           |  |  | 3792 |         $data->timemodified = time();
 | 
        
           |  |  | 3793 |         $DB->update_record('data', $data);
 | 
        
           |  |  | 3794 |         $event = \core\event\course_module_updated::create_from_cm($coursemodule, $context);
 | 
        
           |  |  | 3795 |         $event->trigger();
 | 
        
           |  |  | 3796 |     }
 | 
        
           |  |  | 3797 | }
 | 
        
           |  |  | 3798 |   | 
        
           |  |  | 3799 | /**
 | 
        
           |  |  | 3800 |  * Callback to fetch the activity event type lang string.
 | 
        
           |  |  | 3801 |  *
 | 
        
           |  |  | 3802 |  * @param string $eventtype The event type.
 | 
        
           |  |  | 3803 |  * @return lang_string The event type lang string.
 | 
        
           |  |  | 3804 |  */
 | 
        
           |  |  | 3805 | function mod_data_core_calendar_get_event_action_string(string $eventtype): string {
 | 
        
           |  |  | 3806 |     $modulename = get_string('modulename', 'data');
 | 
        
           |  |  | 3807 |   | 
        
           |  |  | 3808 |     switch ($eventtype) {
 | 
        
           |  |  | 3809 |         case DATA_EVENT_TYPE_OPEN:
 | 
        
           |  |  | 3810 |             $identifier = 'calendarstart';
 | 
        
           |  |  | 3811 |             break;
 | 
        
           |  |  | 3812 |         case DATA_EVENT_TYPE_CLOSE:
 | 
        
           |  |  | 3813 |             $identifier = 'calendarend';
 | 
        
           |  |  | 3814 |             break;
 | 
        
           |  |  | 3815 |         default:
 | 
        
           |  |  | 3816 |             return get_string('requiresaction', 'calendar', $modulename);
 | 
        
           |  |  | 3817 |     }
 | 
        
           |  |  | 3818 |   | 
        
           |  |  | 3819 |     return get_string($identifier, 'data', $modulename);
 | 
        
           |  |  | 3820 | }
 |