Example #1
0
 /**
  * Test datedelta methods: validate() & is_zero()
  * @dataProvider dataprovider_datedelta
  * @param string $instr The input string.
  * @param bool $isvalid Whether the input string is valid.
  * @param bool $iszero Whether the input string is zero.
  */
 public function test_datedelta($instr, $isvalid, $iszero)
 {
     $this->assertEquals($isvalid, datedelta::validate($instr));
     if ($isvalid === true) {
         $dd = new datedelta($instr);
         $this->assertEquals($iszero, $dd->is_zero());
     }
 }
Example #2
0
 /**
  * Overridden to specially handle timetocomplete and frequency fields.
  */
 function get_data($slashed = false)
 {
     $data = parent::get_data($slashed);
     if (!empty($data)) {
         $datedelta = new datedelta($data->timetocomplete);
         $data->timetocomplete = $datedelta->getDateString();
         $datedelta = new datedelta($data->frequency);
         $data->frequency = $datedelta->getDateString();
     }
     return $data;
 }
 /**
  * Check for any curriculum completed nags that need to be handled.
  */
 public static function check_for_completed_nags()
 {
     global $CFG, $CURMAN;
     /// Completed curricula:
     $select = "SELECT cce.id as id, cce.credits AS curcredits, " . "cur.id as curid, cur.reqcredits as reqcredits, " . "cca.id as curassid, cca.userid, cca.curriculumid, cca.completed, cca.timecompleted, " . "cca.credits, cca.locked, cca.timecreated, cca.certificatecode, cca.timemodified, " . "cca.timeexpired, ccc.courseid as courseid ";
     /// >* This will return ALL class enrolment records for a user's curriculum assignment.
     $from = "FROM {$CFG->prefix}crlm_curriculum_assignment cca ";
     $join = "INNER JOIN {$CFG->prefix}crlm_user cu ON cu.id = cca.userid " . "INNER JOIN {$CFG->prefix}crlm_curriculum cur ON cca.curriculumid = cur.id " . "INNER JOIN {$CFG->prefix}crlm_curriculum_course ccc ON ccc.curriculumid = cur.id " . "INNER JOIN {$CFG->prefix}crlm_course cco ON cco.id = ccc.courseid " . "INNER JOIN {$CFG->prefix}crlm_class ccl ON ccl.courseid = cco.id " . "INNER JOIN {$CFG->prefix}crlm_class_enrolment cce ON (cce.classid = ccl.id) AND (cce.userid = cca.userid) ";
     /// >*
     $where = "WHERE (cca.completed = 0) AND (cce.completestatusid != " . STUSTATUS_NOTCOMPLETE . ") ";
     $order = "ORDER BY cur.id, cca.id ASC ";
     //$groupby = "GROUP BY cca.id HAVING numcredits > cur.reqcredits "; /// The "HAVING" clause limits the returns to completed CURRICULA only.
     $groupby = '';
     $sql = $select . $from . $join . $where . $groupby . $order;
     $curassid = 0;
     $curid = 0;
     $numcredits = 0;
     $reqcredits = 10000;
     /// Initially so a completion event is not triggered.
     $requiredcourseids = array();
     $checkcourses = $requiredcourseids;
     $context = false;
     $curasstempl = new curriculumstudent();
     // used just for its properties.
     $studenttempl = new student();
     // used just for its properties.
     $timenow = time();
     $secondsinaday = 60 * 60 * 24;
     $rs = get_recordset_sql($sql);
     if ($rs) {
         while ($rec = rs_fetch_next_record($rs)) {
             /// Loop through enrolment records grouped by curriculum and curriculum assignments,
             /// counting the credits achieved and looking for all required courses to be complete.
             /// Load a new curriculum assignment
             if ($curassid != $rec->curassid) {
                 /// Check for completion - all credits have been earned and all required courses completed
                 if ($curassid && $numcredits >= $reqcredits && empty($checkcourses)) {
                     $currstudent->complete($timenow, $numcredits, 1);
                 }
                 $curassid = $rec->curassid;
                 $curassdata = array();
                 foreach ($curasstempl->properties as $prop => $type) {
                     $curassdata[$prop] = $rec->{$prop};
                 }
                 $curassdata['id'] = $rec->curassid;
                 $currstudent = new curriculumstudent($curassdata);
                 $numcredits = 0;
                 $checkcourses = $requiredcourseids;
             }
             /// Get a new list of required courses.
             if ($curid != $rec->curid) {
                 $curid = $rec->curid;
                 $reqcredits = $rec->reqcredits;
                 $select = 'curriculumid = ' . $curid . ' AND required = 1';
                 if (!($requiredcourseids = get_records_select('crlm_curriculum_course', $select, '', 'courseid,required'))) {
                     $requiredcourseids = array();
                 }
                 $checkcourses = $requiredcourseids;
             }
             /// Track data for completion...
             $numcredits += $rec->curcredits;
             if (isset($checkcourses[$rec->courseid])) {
                 unset($checkcourses[$rec->courseid]);
             }
         }
     }
     /// Check for last record completion - all credits have been earned and all required courses completed
     if ($curassid && $numcredits >= $reqcredits && empty($checkcourses)) {
         $currstudent->complete($timenow, $numcredits, 1);
     }
     $sendtouser = $CURMAN->config->notify_curriculumnotcompleted_user;
     $sendtorole = $CURMAN->config->notify_curriculumnotcompleted_role;
     $sendtosupervisor = $CURMAN->config->notify_curriculumnotcompleted_supervisor;
     /// If nobody receives a notification, we're done.
     if (!$sendtouser && !$sendtorole && !$sendtosupervisor) {
         return true;
     }
     /// Incomplete curricula:
     $select = "SELECT cca.id as id, cca.userid, cca.curriculumid, cca.completed, cca.timecompleted, " . "cca.credits, cca.locked, cca.timecreated, cca.timemodified, " . "cur.id as curid, cur.timetocomplete as timetocomplete ";
     /// >* This will return ALL class enrolment records for a user's curriculum assignment.
     $from = "FROM {$CFG->prefix}crlm_curriculum_assignment cca ";
     $join = "INNER JOIN {$CFG->prefix}crlm_user cu ON cu.id = cca.userid " . "INNER JOIN {$CFG->prefix}crlm_curriculum cur ON cca.curriculumid = cur.id " . "LEFT JOIN {$CFG->prefix}crlm_notification_log cnl ON cnl.fromuserid = cu.id AND cnl.instance = cca.id AND " . "cnl.event = 'curriculum_notcompleted' ";
     $where = "WHERE (cca.completed = 0) AND (cur.timetocomplete != '') AND (cur.timetocomplete NOT LIKE '0h, 0d, 0w, 0m, 0y%') AND cnl.id IS NULL ";
     $order = "ORDER BY cur.id, cca.id ASC ";
     $groupby = '';
     $sql = $select . $from . $join . $where . $groupby . $order;
     $context = false;
     $curasstempl = new curriculumstudent();
     // used just for its properties.
     $studenttempl = new student();
     // used just for its properties.
     $timenow = time();
     $secondsinaday = 60 * 60 * 24;
     $rs = get_recordset_sql($sql);
     if ($rs) {
         while ($rec = rs_fetch_next_record($rs)) {
             /// Loop through curriculum assignments checking for nags.
             $deltad = new datedelta($rec->timetocomplete);
             /// Need to fit this into the SQL instead.
             $reqcompletetime = $rec->timecreated + $deltad->gettimestamp();
             /// If no time to completion set, it has no completion restriction.
             if ($reqcompletetime == 0) {
                 continue;
             }
             $daysfrom = ($reqcompletetime - $timenow) / $secondsinaday;
             if ($daysfrom <= $CURMAN->config->notify_curriculumnotcompleted_days) {
                 $curstudent = new curriculumstudent($rec);
                 mtrace("Triggering curriculum_notcompleted event.\n");
                 events_trigger('curriculum_notcompleted', $curstudent);
             }
         }
     }
     return true;
 }
Example #4
0
 /**
  * Performs program update
  * @throws moodle_exception If there was an error in passed parameters.
  * @throws data_object_exception If there was an error creating the entity.
  * @param array $data The incoming data parameter.
  * @return array An array of parameters, if successful.
  */
 public static function program_update(array $data)
 {
     global $USER, $DB;
     if (static::require_elis_dependencies() !== true) {
         throw new moodle_exception('ws_function_requires_elis', 'local_datahub');
     }
     // Parameter validation.
     $params = self::validate_parameters(self::program_update_parameters(), array('data' => $data));
     // Context validation.
     $context = context_user::instance($USER->id);
     self::validate_context($context);
     $data = (object) $data;
     // Validate program exists
     if (!($curid = $DB->get_field(curriculum::TABLE, 'id', array('idnumber' => $data->idnumber)))) {
         throw new data_object_exception('ws_program_update_fail_invalid_idnumber', 'local_datahub', '', $data);
     }
     // Capability checking.
     require_capability('local/elisprogram:program_edit', \local_elisprogram\context\program::instance($curid));
     // More validation
     if (isset($data->reqcredits)) {
         $reqcredits = (string) $data->reqcredits;
         $digits = strlen($reqcredits);
         $decies = 0;
         if (($decpos = strpos($reqcredits, '.')) !== false) {
             $decies = $digits - $decpos - 1;
             $digits = $decpos;
         }
         if (!is_numeric($reqcredits) || $digits > 8 || $decies > 2) {
             throw new data_object_exception('ws_program_update_fail_invalid_reqcredits', 'local_datahub', '', $data);
         }
     }
     if (isset($data->timetocomplete)) {
         $datedelta = new datedelta($data->timetocomplete);
         if (!$datedelta->getDateString()) {
             throw new data_object_exception('ws_program_update_fail_invalid_timetocomplete', 'local_datahub', '', $data);
         }
     }
     if (isset($data->frequency)) {
         $datedelta = new datedelta($data->frequency);
         if (!$datedelta->getDateString()) {
             throw new data_object_exception('ws_program_update_fail_invalid_frequency', 'local_datahub', '', $data);
         }
     }
     if (isset($data->priority)) {
         if ($data->priority < 0 || $data->priority > 10) {
             throw new data_object_exception('ws_program_update_fail_invalid_priority', 'local_datahub', '', $data);
         }
     }
     $prg = new curriculum($curid);
     $prg->load();
     $prg->set_from_data($data);
     $prg->save();
     // Respond.
     if (!empty($prg->id)) {
         $prgrec = (array) $DB->get_record(curriculum::TABLE, array('id' => $prg->id));
         $prgobj = $prg->to_array();
         // convert multi-valued custom field arrays to comma-separated listing
         $fields = self::get_program_custom_fields();
         foreach ($fields as $field) {
             // Generate name using custom field prefix.
             $fullfieldname = data_object_with_custom_fields::CUSTOM_FIELD_PREFIX . $field->shortname;
             if ($field->multivalued && isset($prgobj[$fullfieldname]) && is_array($prgobj[$fullfieldname])) {
                 $prgobj[$fullfieldname] = implode(',', $prgobj[$fullfieldname]);
             }
         }
         return array('messagecode' => get_string('ws_program_update_success_code', 'local_datahub'), 'message' => get_string('ws_program_update_success_msg', 'local_datahub'), 'record' => array_merge($prgrec, $prgobj));
     } else {
         throw new data_object_exception('ws_program_update_fail', 'local_datahub');
     }
 }
Example #5
0
 /**
  * Validates that program fields are set to valid values, if they are set
  * on the import record
  *
  * @param string $action One of 'create' or 'update'
  * @param object $record The import record
  *
  * @return boolean true if the record validates correctly, otherwise false
  */
 function validate_program_data($action, $record, $filename)
 {
     global $CFG, $DB;
     require_once $CFG->dirroot . '/local/elisprogram/lib/datedelta.class.php';
     if (isset($record->reqcredits)) {
         $digits = strlen(substr($record->reqcredits, 0, strpos($record->reqcredits, '.')));
         $decdigits = strlen(substr(strrchr($record->reqcredits, '.'), 1));
         if (!is_numeric($record->reqcredits) || $decdigits > 2 || $digits > 8) {
             $identifier = $this->get_field_mapping('reqcredits');
             $this->fslogger->log_failure("{$identifier} value of \"{$record->reqcredits}\" is not a number with at most ten total digits and two decimal digits.", 0, $filename, $this->linenumber, $record, "curriculum");
             return false;
         }
     }
     if (isset($record->timetocomplete)) {
         $datedelta = new datedelta($record->timetocomplete);
         if (!$datedelta->getDateString()) {
             $identifier = $this->get_field_mapping('timetocomplete');
             $this->fslogger->log_failure("{$identifier} value of \"{$record->timetocomplete}\" is not a valid time delta in *h, *d, *w, *m, *y format.", 0, $filename, $this->linenumber, $record, "curriculum");
             return false;
         }
     }
     if (isset($record->frequency)) {
         $enabled = (bool) get_config('local_elisprogram', 'enable_curriculum_expiration');
         if ($enabled) {
             $datedelta = new datedelta($record->frequency);
             if (!$datedelta->getDateString()) {
                 $identifier = $this->get_field_mapping('frequency');
                 $this->fslogger->log_failure("{$identifier} value of \"{$record->frequency}\" is not a valid time delta in *h, *d, *w, *m, *y format.", 0, $filename, $this->linenumber, $record, "curriculum");
                 return false;
             }
         } else {
             $identifier = $this->get_field_mapping('frequency');
             $this->fslogger->log_failure("Program {$identifier} / expiration cannot be set because program expiration is globally disabled.", 0, $filename, $this->linenumber, $record, "curriculum");
             return false;
         }
     }
     if (isset($record->priority)) {
         if ($record->priority < 0 || $record->priority > 10) {
             $identifier = $this->get_field_mapping('priority');
             $this->fslogger->log_failure("{$identifier} value of \"{$record->priority}\" is not one of the available options (0 .. 10).", 0, $filename, $this->linenumber, $record, "curriculum");
             return false;
         }
     }
     return true;
 }
Example #6
0
 /**
  * Check for any curriculum completed nags that need to be handled.
  * @return boolean True if successful, otherwise false.
  */
 public static function check_for_completed_nags()
 {
     global $CFG, $DB;
     // Completed curricula:
     $select = 'SELECT cce.id as id, cce.credits AS curcredits, cce.completetime AS clscomplete,
                 cur.id as curid, cur.reqcredits as reqcredits,
                 cca.id as curassid, cca.userid, cca.curriculumid, cca.completed, cca.timecompleted,
                 cca.credits, cca.locked, cca.timecreated, cca.timemodified, cca.timeexpired,
                 ccc.courseid as courseid, ccc.required AS crsrequired ';
     // >* This will return ALL class enrolment records for a user's curriculum assignment.
     $from = 'FROM {' . curriculumstudent::TABLE . '} cca ';
     $join = 'INNER JOIN {' . user::TABLE . '} cu ON cu.id = cca.userid
                 INNER JOIN {' . curriculum::TABLE . '} cur ON cca.curriculumid = cur.id
                 INNER JOIN {' . curriculumcourse::TABLE . '} ccc ON ccc.curriculumid = cur.id
                 INNER JOIN {' . course::TABLE . '} cco ON cco.id = ccc.courseid
                 INNER JOIN {' . pmclass::TABLE . '} ccl ON ccl.courseid = cco.id
                 INNER JOIN {' . student::TABLE . '} cce ON (cce.classid = ccl.id) AND (cce.userid = cca.userid) ';
     // >*
     $where = 'WHERE (cca.completed = 0) AND (cce.completestatusid != ' . STUSTATUS_NOTCOMPLETE . ') ';
     $order = 'ORDER BY cur.id, cca.id ASC ';
     $sql = $select . $from . $join . $where . $order;
     $curassid = 0;
     $curid = 0;
     $numcredits = 0;
     $reqcredits = 10000;
     // Initially so a completion event is not triggered.
     $requiredcourseids = array();
     $checkcourses = $requiredcourseids;
     $context = false;
     $timenow = 0;
     $timerun = time();
     $secondsinaday = 60 * 60 * 24;
     $rs = $DB->get_recordset_sql($sql);
     if ($rs) {
         foreach ($rs as $rec) {
             // Loop through enrolment records grouped by curriculum and curriculum assignments,
             // counting the credits achieved and looking for all required courses to be complete.
             // Load a new curriculum assignment.
             if ($curassid != $rec->curassid) {
                 // Check for completion - all credits have been earned and all required courses completed.
                 if ($curassid && $numcredits >= $reqcredits && empty($checkcourses)) {
                     $currstudent->complete($timenow ? $timenow : $timerun, $numcredits, 1);
                     $timenow = 0;
                 }
                 $curassid = $rec->curassid;
                 $currstudent = new curriculumstudent($rec->curassid);
                 $currstudent->load();
                 $numcredits = 0;
                 $checkcourses = $requiredcourseids;
             }
             if (!empty($rec->crsrequired) && $rec->clscomplete > $timenow) {
                 $timenow = $rec->clscomplete;
             }
             // Get a new list of required courses.
             if ($curid != $rec->curid) {
                 $curid = $rec->curid;
                 $reqcredits = $rec->reqcredits;
                 $select = 'curriculumid = ' . $curid . ' AND required = 1';
                 if (!($requiredcourseids = $DB->get_records_select(curriculumcourse::TABLE, $select, null, '', 'courseid,required'))) {
                     $requiredcourseids = array();
                 }
                 $checkcourses = $requiredcourseids;
             }
             // Track data for completion...
             $numcredits += $rec->curcredits;
             if (isset($checkcourses[$rec->courseid])) {
                 unset($checkcourses[$rec->courseid]);
             }
         }
     }
     // Check for last record completion - all credits have been earned and all required courses completed.
     if ($curassid && $numcredits >= $reqcredits && empty($checkcourses)) {
         $currstudent->complete($timenow ? $timenow : $timerun, $numcredits, 1);
     }
     $sendtouser = elis::$config->local_elisprogram->notify_curriculumnotcompleted_user;
     $sendtorole = elis::$config->local_elisprogram->notify_curriculumnotcompleted_role;
     $sendtosupervisor = elis::$config->local_elisprogram->notify_curriculumnotcompleted_supervisor;
     // If nobody receives a notification, we're done.
     if (!$sendtouser && !$sendtorole && !$sendtosupervisor) {
         return true;
     }
     // Incomplete curricula:
     $select = 'SELECT cca.id as id, cca.userid, cca.curriculumid, cca.completed, cca.timecompleted, cca.credits,
                 cca.locked, cca.timecreated, cca.certificatecode, cca.timemodified, cur.id as curid,
                 cur.timetocomplete as timetocomplete ';
     $from = 'FROM {' . curriculumstudent::TABLE . '} cca ';
     $join = 'INNER JOIN {' . user::TABLE . '} cu ON cu.id = cca.userid
                 INNER JOIN {' . curriculum::TABLE . '} cur ON cca.curriculumid = cur.id
                 LEFT JOIN {' . notificationlog::TABLE . '} cnl ON cnl.fromuserid = cu.id AND cnl.instance = cca.id AND
                 cnl.event = \'curriculum_notcompleted\' ';
     $where = 'WHERE (cca.completed = 0) AND (cur.timetocomplete != \'\') AND (cur.timetocomplete NOT LIKE \'0h, 0d, 0w, 0m, 0y%\') AND cnl.id IS NULL ';
     $order = 'ORDER BY cur.id, cca.id ASC ';
     $sql = $select . $from . $join . $where . $order;
     $context = false;
     $timenow = time();
     $secondsinaday = 60 * 60 * 24;
     $rs = $DB->get_recordset_sql($sql);
     if ($rs) {
         foreach ($rs as $rec) {
             // Loop through curriculum assignments checking for nags.
             $deltad = new datedelta($rec->timetocomplete);
             // Need to fit this into the SQL instead.
             $reqcompletetime = $rec->timecreated + $deltad->gettimestamp();
             // If no time to completion set, it has no completion restriction.
             if ($reqcompletetime == 0) {
                 continue;
             }
             $daysfrom = ($reqcompletetime - $timenow) / $secondsinaday;
             if ($daysfrom <= elis::$config->local_elisprogram->notify_curriculumnotcompleted_days) {
                 events_trigger('curriculum_notcompleted', $rec);
             }
         }
     }
     return true;
 }