. /** * Library of functions and constants for module attendance * * @package mod_attendance * @copyright 2011 Artem Andreev * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); require_once(dirname(__FILE__) . '/classes/calendar_helpers.php'); /** * Returns the information if the module supports a feature * * @see plugin_supports() in lib/moodlelib.php * @param string $feature FEATURE_xx constant for requested feature * @return mixed true if the feature is supported, null if unknown */ function attendance_supports($feature) { switch($feature) { case FEATURE_GRADE_HAS_GRADE: return true; case FEATURE_GROUPS: return true; case FEATURE_GROUPINGS: return true; case FEATURE_SHOW_DESCRIPTION: return true; case FEATURE_MOD_INTRO: return true; case FEATURE_BACKUP_MOODLE2: return true; // Artem Andreev: AFAIK it's not tested. case FEATURE_COMPLETION_TRACKS_VIEWS: return false; default: return null; } } /** * Add default set of statuses to the new attendance. * * @param int $attid - id of attendance instance. */ function att_add_default_statuses($attid) { global $DB; $statuses = $DB->get_recordset('attendance_statuses', array('attendanceid' => 0), 'id'); foreach ($statuses as $st) { $rec = $st; $rec->attendanceid = $attid; $DB->insert_record('attendance_statuses', $rec); } $statuses->close(); } /** * Add default set of warnings to the new attendance. * * @param int $id - id of attendance instance. */ function attendance_add_default_warnings($id) { global $DB, $CFG; require_once($CFG->dirroot.'/mod/attendance/locallib.php'); $warnings = $DB->get_recordset('attendance_warning', array('idnumber' => 0), 'id'); foreach ($warnings as $n) { $rec = $n; $rec->idnumber = $id; $DB->insert_record('attendance_warning', $rec); } $warnings->close(); } /** * Add new attendance instance. * * @param stdClass $attendance * @return bool|int */ function attendance_add_instance($attendance) { global $DB; $attendance->timemodified = time(); // Default grade (similar to what db fields defaults if no grade attribute is passed), // but we need it in object for grading update. if (!isset($attendance->grade)) { $attendance->grade = 100; } $attendance->id = $DB->insert_record('attendance', $attendance); att_add_default_statuses($attendance->id); attendance_add_default_warnings($attendance->id); attendance_grade_item_update($attendance); return $attendance->id; } /** * Update existing attendance instance. * * @param stdClass $attendance * @return bool */ function attendance_update_instance($attendance) { global $DB; $attendance->timemodified = time(); $attendance->id = $attendance->instance; if (! $DB->update_record('attendance', $attendance)) { return false; } attendance_grade_item_update($attendance); return true; } /** * Delete existing attendance * * @param int $id * @return bool */ function attendance_delete_instance($id) { global $DB, $CFG; require_once($CFG->dirroot.'/mod/attendance/locallib.php'); if (! $attendance = $DB->get_record('attendance', array('id' => $id))) { return false; } if ($sessids = array_keys($DB->get_records('attendance_sessions', array('attendanceid' => $id), '', 'id'))) { if (attendance_existing_calendar_events_ids($sessids)) { attendance_delete_calendar_events($sessids); } $DB->delete_records_list('attendance_log', 'sessionid', $sessids); $DB->delete_records('attendance_sessions', array('attendanceid' => $id)); } $DB->delete_records('attendance_statuses', array('attendanceid' => $id)); $DB->delete_records('attendance_warning', array('idnumber' => $id)); $DB->delete_records('attendance', array('id' => $id)); attendance_grade_item_delete($attendance); return true; } /** * Called by course/reset.php * @param moodleform $mform form passed by reference */ function attendance_reset_course_form_definition(&$mform) { $mform->addElement('header', 'attendanceheader', get_string('modulename', 'attendance')); $mform->addElement('static', 'description', get_string('description', 'attendance'), get_string('resetdescription', 'attendance')); $mform->addElement('checkbox', 'reset_attendance_log', get_string('deletelogs', 'attendance')); $mform->addElement('checkbox', 'reset_attendance_sessions', get_string('deletesessions', 'attendance')); $mform->disabledIf('reset_attendance_sessions', 'reset_attendance_log', 'notchecked'); $mform->addElement('checkbox', 'reset_attendance_statuses', get_string('resetstatuses', 'attendance')); $mform->setAdvanced('reset_attendance_statuses'); $mform->disabledIf('reset_attendance_statuses', 'reset_attendance_log', 'notchecked'); } /** * Course reset form defaults. * * @param stdClass $course * @return array */ function attendance_reset_course_form_defaults($course) { return array('reset_attendance_log' => 0, 'reset_attendance_statuses' => 0, 'reset_attendance_sessions' => 0); } /** * Reset user data within attendance. * * @param stdClass $data * @return array */ function attendance_reset_userdata($data) { global $DB; $status = array(); $attids = array_keys($DB->get_records('attendance', array('course' => $data->courseid), '', 'id')); if (!empty($data->reset_attendance_log)) { $sess = $DB->get_records_list('attendance_sessions', 'attendanceid', $attids, '', 'id'); if (!empty($sess)) { list($sql, $params) = $DB->get_in_or_equal(array_keys($sess)); $DB->delete_records_select('attendance_log', "sessionid $sql", $params); list($sql, $params) = $DB->get_in_or_equal($attids); $DB->set_field_select('attendance_sessions', 'lasttaken', 0, "attendanceid $sql", $params); if (empty($data->reset_attendance_sessions)) { // If sessions are being retained, clear automarkcompleted value. $DB->set_field_select('attendance_sessions', 'automarkcompleted', 0, "attendanceid $sql", $params); } $status[] = array( 'component' => get_string('modulenameplural', 'attendance'), 'item' => get_string('attendancedata', 'attendance'), 'error' => false ); } } if (!empty($data->reset_attendance_statuses)) { $DB->delete_records_list('attendance_statuses', 'attendanceid', $attids); foreach ($attids as $attid) { att_add_default_statuses($attid); } $status[] = array( 'component' => get_string('modulenameplural', 'attendance'), 'item' => get_string('sessions', 'attendance'), 'error' => false ); } if (!empty($data->reset_attendance_sessions)) { $sessionsids = array_keys($DB->get_records_list('attendance_sessions', 'attendanceid', $attids, '', 'id')); if (attendance_existing_calendar_events_ids($sessionsids)) { attendance_delete_calendar_events($sessionsids); } $DB->delete_records_list('attendance_sessions', 'attendanceid', $attids); $status[] = array( 'component' => get_string('modulenameplural', 'attendance'), 'item' => get_string('statuses', 'attendance'), 'error' => false ); } return $status; } /** * Return a small object with summary information about what a * user has done with a given particular instance of this module * Used for user activity reports. * $return->time = the time they did it * $return->info = a short text description * * @param stdClass $course - full course record. * @param stdClass $user - full user record * @param stdClass $mod * @param stdClass $attendance * @return stdClass. */ function attendance_user_outline($course, $user, $mod, $attendance) { global $CFG; require_once(dirname(__FILE__).'/locallib.php'); require_once($CFG->libdir.'/gradelib.php'); $grades = grade_get_grades($course->id, 'mod', 'attendance', $attendance->id, $user->id); $result = new stdClass(); if (!empty($grades->items[0]->grades)) { $grade = reset($grades->items[0]->grades); $result->time = $grade->dategraded; } else { $result->time = 0; } if (has_capability('mod/attendance:canbelisted', $mod->context, $user->id)) { $summary = new mod_attendance_summary($attendance->id, $user->id); $usersummary = $summary->get_all_sessions_summary_for($user->id); $result->info = $usersummary->pointsallsessions; } return $result; } /** * Print a detailed representation of what a user has done with * a given particular instance of this module, for user activity reports. * * @param stdClass $course * @param stdClass $user * @param stdClass $mod * @param stdClass $attendance */ function attendance_user_complete($course, $user, $mod, $attendance) { global $CFG; require_once(dirname(__FILE__).'/renderhelpers.php'); require_once($CFG->libdir.'/gradelib.php'); if (has_capability('mod/attendance:canbelisted', $mod->context, $user->id)) { echo construct_full_user_stat_html_table($attendance, $user); } } /** * Dummy function - must exist to allow quick editing of module name. * * @param stdClass $attendance * @param int $userid * @param bool $nullifnone */ function attendance_update_grades($attendance, $userid=0, $nullifnone=true) { // We need this function to exist so that quick editing of module name is passed to gradebook. } /** * Create grade item for given attendance * * @param stdClass $attendance object with extra cmidnumber * @param mixed $grades optional array/object of grade(s); 'reset' means reset grades in gradebook * @return int 0 if ok, error code otherwise */ function attendance_grade_item_update($attendance, $grades=null) { global $CFG, $DB; require_once('locallib.php'); if (!function_exists('grade_update')) { // Workaround for buggy PHP versions. require_once($CFG->libdir.'/gradelib.php'); } if (!isset($attendance->courseid)) { $attendance->courseid = $attendance->course; } if (!$DB->get_record('course', array('id' => $attendance->course))) { error("Course is misconfigured"); } if (!empty($attendance->cmidnumber)) { $params = array('itemname' => $attendance->name, 'idnumber' => $attendance->cmidnumber); } else { // MDL-14303. $params = array('itemname' => $attendance->name); } if ($attendance->grade > 0) { $params['gradetype'] = GRADE_TYPE_VALUE; $params['grademax'] = $attendance->grade; $params['grademin'] = 0; } else if ($attendance->grade < 0) { $params['gradetype'] = GRADE_TYPE_SCALE; $params['scaleid'] = -$attendance->grade; } else { $params['gradetype'] = GRADE_TYPE_NONE; } if ($grades === 'reset') { $params['reset'] = true; $grades = null; } return grade_update('mod/attendance', $attendance->courseid, 'mod', 'attendance', $attendance->id, 0, $grades, $params); } /** * Delete grade item for given attendance * * @param object $attendance object * @return object attendance */ function attendance_grade_item_delete($attendance) { global $CFG; require_once($CFG->libdir.'/gradelib.php'); if (!isset($attendance->courseid)) { $attendance->courseid = $attendance->course; } return grade_update('mod/attendance', $attendance->courseid, 'mod', 'attendance', $attendance->id, 0, null, array('deleted' => 1)); } /** * This function returns if a scale is being used by one attendance * it it has support for grading and scales. Commented code should be * modified if necessary. See book, glossary or journal modules * as reference. * * @param int $attendanceid * @param int $scaleid * @return boolean True if the scale is used by any attendance */ function attendance_scale_used ($attendanceid, $scaleid) { return false; } /** * Checks if scale is being used by any instance of attendance * * This is used to find out if scale used anywhere * * @param int $scaleid * @return bool true if the scale is used by any book */ function attendance_scale_used_anywhere($scaleid) { return false; } /** * Serves the attendance sessions descriptions files. * * @param object $course * @param object $cm * @param object $context * @param string $filearea * @param array $args * @param bool $forcedownload * @return bool false if file not found, does not return if found - justsend the file */ function attendance_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) { global $DB; if ($context->contextlevel != CONTEXT_MODULE) { return false; } require_login($course, false, $cm); if (!$DB->record_exists('attendance', array('id' => $cm->instance))) { return false; } // Session area is served by pluginfile.php. $fileareas = array('session'); if (!in_array($filearea, $fileareas)) { return false; } $sessid = (int)array_shift($args); if (!$DB->record_exists('attendance_sessions', array('id' => $sessid))) { return false; } $fs = get_file_storage(); $relativepath = implode('/', $args); $fullpath = "/$context->id/mod_attendance/$filearea/$sessid/$relativepath"; if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { return false; } send_stored_file($file, 0, 0, true); } /** * Print tabs on attendance settings page. * * @param string $selected - current selected tab. */ function attendance_print_settings_tabs($selected = 'settings') { global $CFG; // Print tabs for different settings pages. $tabs = array(); $tabs[] = new tabobject('settings', "{$CFG->wwwroot}/{$CFG->admin}/settings.php?section=modsettingattendance", get_string('settings', 'attendance'), get_string('settings'), false); $tabs[] = new tabobject('defaultstatus', $CFG->wwwroot.'/mod/attendance/defaultstatus.php', get_string('defaultstatus', 'attendance'), get_string('defaultstatus', 'attendance'), false); if (get_config('attendance', 'enablewarnings')) { $tabs[] = new tabobject('defaultwarnings', $CFG->wwwroot . '/mod/attendance/warnings.php', get_string('defaultwarnings', 'attendance'), get_string('defaultwarnings', 'attendance'), false); } $tabs[] = new tabobject('coursesummary', $CFG->wwwroot.'/mod/attendance/coursesummary.php', get_string('coursesummary', 'attendance'), get_string('coursesummary', 'attendance'), false); if (get_config('attendance', 'enablewarnings')) { $tabs[] = new tabobject('absentee', $CFG->wwwroot . '/mod/attendance/absentee.php', get_string('absenteereport', 'attendance'), get_string('absenteereport', 'attendance'), false); } $tabs[] = new tabobject('resetcalendar', $CFG->wwwroot.'/mod/attendance/resetcalendar.php', get_string('resetcalendar', 'attendance'), get_string('resetcalendar', 'attendance'), false); $tabs[] = new tabobject('importsessions', $CFG->wwwroot . '/mod/attendance/import/sessions.php', get_string('importsessions', 'attendance'), get_string('importsessions', 'attendance'), false); ob_start(); print_tabs(array($tabs), $selected); $tabmenu = ob_get_contents(); ob_end_clean(); return $tabmenu; } /** * Helper function to remove a user from the thirdpartyemails record of the attendance_warning table. * * @param array $warnings - list of warnings to parse. * @param int $userid - User id of user to remove. */ function attendance_remove_user_from_thirdpartyemails($warnings, $userid) { global $DB; // Update the third party emails list for all the relevant warnings. $updatedwarnings = array_map( function(stdClass $warning) use ($userid) : stdClass { $warning->thirdpartyemails = implode(',', array_diff(explode(',', $warning->thirdpartyemails), [$userid])); return $warning; }, array_filter( $warnings, function (stdClass $warning) use ($userid) : bool { return in_array($userid, explode(',', $warning->thirdpartyemails)); } ) ); // Sadly need to update each individually, no way to bulk update as all the thirdpartyemails field can be different. foreach ($updatedwarnings as $updatedwarning) { $DB->update_record('attendance_warning', $updatedwarning); } }