418 lines
14 KiB
PHP
418 lines
14 KiB
PHP
<?php
|
|
// This file is part of the htmlcert module for Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* Provides functionality needed by htmlcert activities.
|
|
*
|
|
* @package mod_htmlcert
|
|
* @copyright 2016 Mark Nelson <markn@moodle.com>, 2021 Klaus-Uwe Mitterer <kumitterer@kumi.systems>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
namespace mod_htmlcert;
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
/**
|
|
* Class certificate.
|
|
*
|
|
* Helper functionality for certificates.
|
|
*
|
|
* @package mod_htmlcert
|
|
* @copyright 2016 Mark Nelson <markn@moodle.com>, 2021 Klaus-Uwe Mitterer <kumitterer@kumi.systems>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
class certificate {
|
|
|
|
/**
|
|
* Send the file inline to the browser.
|
|
*/
|
|
const DELIVERY_OPTION_INLINE = 'I';
|
|
|
|
/**
|
|
* Send to the browser and force a file download
|
|
*/
|
|
const DELIVERY_OPTION_DOWNLOAD = 'D';
|
|
|
|
/**
|
|
* @var string the print protection variable
|
|
*/
|
|
const PROTECTION_PRINT = 'print';
|
|
|
|
/**
|
|
* @var string the modify protection variable
|
|
*/
|
|
const PROTECTION_MODIFY = 'modify';
|
|
|
|
/**
|
|
* @var string the copy protection variable
|
|
*/
|
|
const PROTECTION_COPY = 'copy';
|
|
|
|
/**
|
|
* @var int the number of issues that will be displayed on each page in the report
|
|
* If you want to display all htmlcerts on a page set this to 0.
|
|
*/
|
|
const HTMLCERT_PER_PAGE = '50';
|
|
|
|
/**
|
|
* Handles setting the protection field for the htmlcert
|
|
*
|
|
* @param \stdClass $data
|
|
* @return string the value to insert into the protection field
|
|
*/
|
|
public static function set_protection($data) {
|
|
$protection = array();
|
|
|
|
if (!empty($data->protection_print)) {
|
|
$protection[] = self::PROTECTION_PRINT;
|
|
}
|
|
if (!empty($data->protection_modify)) {
|
|
$protection[] = self::PROTECTION_MODIFY;
|
|
}
|
|
if (!empty($data->protection_copy)) {
|
|
$protection[] = self::PROTECTION_COPY;
|
|
}
|
|
|
|
// Return the protection string.
|
|
return implode(', ', $protection);
|
|
}
|
|
|
|
/**
|
|
* Handles uploading an image for the htmlcert module.
|
|
*
|
|
* @param int $draftitemid the draft area containing the files
|
|
* @param int $contextid the context we are storing this image in
|
|
* @param string $filearea indentifies the file area.
|
|
*/
|
|
public static function upload_files($draftitemid, $contextid, $filearea = 'image') {
|
|
global $CFG;
|
|
|
|
// Save the file if it exists that is currently in the draft area.
|
|
require_once($CFG->dirroot . '/lib/filelib.php');
|
|
file_save_draft_area_files($draftitemid, $contextid, 'mod_htmlcert', $filearea, 0);
|
|
}
|
|
|
|
/**
|
|
* Get the time the user has spent in the course.
|
|
*
|
|
* @param int $courseid
|
|
* @param int $userid
|
|
* @return int the total time spent in seconds
|
|
*/
|
|
public static function get_course_time(int $courseid, int $userid = 0): int {
|
|
global $CFG, $DB, $USER;
|
|
|
|
if (empty($userid)) {
|
|
$userid = $USER->id;
|
|
}
|
|
|
|
$logmanager = get_log_manager();
|
|
$readers = $logmanager->get_readers();
|
|
$enabledreaders = get_config('tool_log', 'enabled_stores');
|
|
if (empty($enabledreaders)) {
|
|
return 0;
|
|
}
|
|
$enabledreaders = explode(',', $enabledreaders);
|
|
|
|
// Go through all the readers until we find one that we can use.
|
|
foreach ($enabledreaders as $enabledreader) {
|
|
$reader = $readers[$enabledreader];
|
|
if ($reader instanceof \logstore_legacy\log\store) {
|
|
$logtable = 'log';
|
|
$coursefield = 'course';
|
|
$timefield = 'time';
|
|
break;
|
|
} else if ($reader instanceof \core\log\sql_internal_table_reader) {
|
|
$logtable = $reader->get_internal_log_table_name();
|
|
$coursefield = 'courseid';
|
|
$timefield = 'timecreated';
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we didn't find a reader then return 0.
|
|
if (!isset($logtable)) {
|
|
return 0;
|
|
}
|
|
|
|
$sql = "SELECT id, $timefield
|
|
FROM {{$logtable}}
|
|
WHERE userid = :userid
|
|
AND $coursefield = :courseid
|
|
ORDER BY $timefield ASC";
|
|
$params = array('userid' => $userid, 'courseid' => $courseid);
|
|
$totaltime = 0;
|
|
if ($logs = $DB->get_recordset_sql($sql, $params)) {
|
|
foreach ($logs as $log) {
|
|
if (!isset($login)) {
|
|
// For the first time $login is not set so the first log is also the first login.
|
|
$login = $log->$timefield;
|
|
$lasthit = $log->$timefield;
|
|
$totaltime = 0;
|
|
}
|
|
$delay = $log->$timefield - $lasthit;
|
|
if ($delay > $CFG->sessiontimeout) {
|
|
// The difference between the last log and the current log is more than
|
|
// the timeout Register session value so that we have found a session!
|
|
$login = $log->$timefield;
|
|
} else {
|
|
$totaltime += $delay;
|
|
}
|
|
// Now the actual log became the previous log for the next cycle.
|
|
$lasthit = $log->$timefield;
|
|
}
|
|
|
|
return $totaltime;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of issued htmlcerts.
|
|
*
|
|
* @param int $htmlcertid
|
|
* @param bool $groupmode are we in group mode
|
|
* @param \stdClass $cm the course module
|
|
* @param int $limitfrom
|
|
* @param int $limitnum
|
|
* @param string $sort
|
|
* @return array the users
|
|
*/
|
|
public static function get_issues($htmlcertid, $groupmode, $cm, $limitfrom, $limitnum, $sort = '') {
|
|
global $DB;
|
|
|
|
// Get the conditional SQL.
|
|
list($conditionssql, $conditionsparams) = self::get_conditional_issues_sql($cm, $groupmode);
|
|
|
|
// If it is empty then return an empty array.
|
|
if (empty($conditionsparams)) {
|
|
return array();
|
|
}
|
|
|
|
// Add the conditional SQL and the htmlcertid to form all used parameters.
|
|
$allparams = $conditionsparams + array('htmlcertid' => $htmlcertid);
|
|
|
|
// Return the issues.
|
|
$context = \context_module::instance($cm->id);
|
|
$extrafields = \core_user\fields::for_identity($context)->get_required_fields();
|
|
|
|
$ufields = \core_user\fields::for_userpic()->including(...$extrafields);
|
|
[
|
|
'selects' => $userfieldsselects,
|
|
'joins' => $userfieldsjoin,
|
|
'params' => $userfieldsparams
|
|
] = (array) $ufields->get_sql('u', true);
|
|
$allparams = array_merge($allparams, $userfieldsparams);
|
|
$sql = "SELECT ci.id as issueid, ci.code, ci.timecreated $userfieldsselects
|
|
FROM {user} u
|
|
INNER JOIN {htmlcert_issues} ci ON u.id = ci.userid
|
|
$userfieldsjoin
|
|
WHERE u.deleted = 0
|
|
AND ci.htmlcertid = :htmlcertid
|
|
$conditionssql";
|
|
if ($sort) {
|
|
$sql .= "ORDER BY " . $sort;
|
|
} else {
|
|
$sql .= "ORDER BY " . $DB->sql_fullname();
|
|
}
|
|
|
|
return $DB->get_records_sql($sql, $allparams, $limitfrom, $limitnum);
|
|
}
|
|
|
|
/**
|
|
* Returns the total number of issues for a given htmlcert.
|
|
*
|
|
* @param int $htmlcertid
|
|
* @param \stdClass $cm the course module
|
|
* @param bool $groupmode the group mode
|
|
* @return int the number of issues
|
|
*/
|
|
public static function get_number_of_issues($htmlcertid, $cm, $groupmode) {
|
|
global $DB;
|
|
|
|
// Get the conditional SQL.
|
|
list($conditionssql, $conditionsparams) = self::get_conditional_issues_sql($cm, $groupmode);
|
|
|
|
// If it is empty then return 0.
|
|
if (empty($conditionsparams)) {
|
|
return 0;
|
|
}
|
|
|
|
// Add the conditional SQL and the htmlcertid to form all used parameters.
|
|
$allparams = $conditionsparams + array('htmlcertid' => $htmlcertid);
|
|
|
|
// Return the number of issues.
|
|
$sql = "SELECT COUNT(u.id) as count
|
|
FROM {user} u
|
|
INNER JOIN {htmlcert_issues} ci
|
|
ON u.id = ci.userid
|
|
WHERE u.deleted = 0
|
|
AND ci.htmlcertid = :htmlcertid
|
|
$conditionssql";
|
|
return $DB->count_records_sql($sql, $allparams);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of the conditional variables to use in the get_issues SQL query.
|
|
*
|
|
* @param \stdClass $cm the course module
|
|
* @param bool $groupmode are we in group mode ?
|
|
* @return array the conditional variables
|
|
*/
|
|
public static function get_conditional_issues_sql($cm, $groupmode) {
|
|
global $DB, $USER;
|
|
|
|
// Get all users that can manage this htmlcert to exclude them from the report.
|
|
$context = \context_module::instance($cm->id);
|
|
$conditionssql = '';
|
|
$conditionsparams = array();
|
|
|
|
// Get all users that can manage this certificate to exclude them from the report.
|
|
$certmanagers = array_keys(get_users_by_capability($context, 'mod/htmlcert:manage', 'u.id'));
|
|
$certmanagers = array_merge($certmanagers, array_keys(get_admins()));
|
|
list($sql, $params) = $DB->get_in_or_equal($certmanagers, SQL_PARAMS_NAMED, 'cert');
|
|
$conditionssql .= "AND NOT u.id $sql \n";
|
|
$conditionsparams += $params;
|
|
|
|
if ($groupmode) {
|
|
$canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
|
|
$currentgroup = groups_get_activity_group($cm);
|
|
|
|
// If we are viewing all participants and the user does not have access to all groups then return nothing.
|
|
if (!$currentgroup && !$canaccessallgroups) {
|
|
return array('', array());
|
|
}
|
|
|
|
if ($currentgroup) {
|
|
if (!$canaccessallgroups) {
|
|
// Guest users do not belong to any groups.
|
|
if (isguestuser()) {
|
|
return array('', array());
|
|
}
|
|
|
|
// Check that the user belongs to the group we are viewing.
|
|
$usersgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid);
|
|
if ($usersgroups) {
|
|
if (!isset($usersgroups[$currentgroup])) {
|
|
return array('', array());
|
|
}
|
|
} else { // They belong to no group, so return an empty array.
|
|
return array('', array());
|
|
}
|
|
}
|
|
|
|
$groupusers = array_keys(groups_get_members($currentgroup, 'u.*'));
|
|
if (empty($groupusers)) {
|
|
return array('', array());
|
|
}
|
|
|
|
list($sql, $params) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED, 'grp');
|
|
$conditionssql .= "AND u.id $sql ";
|
|
$conditionsparams += $params;
|
|
}
|
|
}
|
|
|
|
return array($conditionssql, $conditionsparams);
|
|
}
|
|
|
|
/**
|
|
* Get number of certificates for a user.
|
|
*
|
|
* @param int $userid
|
|
* @return int
|
|
*/
|
|
public static function get_number_of_certificates_for_user($userid) {
|
|
global $DB;
|
|
|
|
$sql = "SELECT COUNT(*)
|
|
FROM {htmlcert} c
|
|
INNER JOIN {htmlcert_issues} ci
|
|
ON c.id = ci.htmlcertid
|
|
WHERE ci.userid = :userid";
|
|
return $DB->count_records_sql($sql, array('userid' => $userid));
|
|
}
|
|
|
|
/**
|
|
* Gets the certificates for the user.
|
|
*
|
|
* @param int $userid
|
|
* @param int $limitfrom
|
|
* @param int $limitnum
|
|
* @param string $sort
|
|
* @return array
|
|
*/
|
|
public static function get_certificates_for_user($userid, $limitfrom, $limitnum, $sort = '') {
|
|
global $DB;
|
|
|
|
if (empty($sort)) {
|
|
$sort = 'ci.timecreated DESC';
|
|
}
|
|
|
|
$sql = "SELECT c.id, c.name, co.fullname as coursename, ci.code, ci.timecreated
|
|
FROM {htmlcert} c
|
|
INNER JOIN {htmlcert_issues} ci
|
|
ON c.id = ci.htmlcertid
|
|
INNER JOIN {course} co
|
|
ON c.course = co.id
|
|
WHERE ci.userid = :userid
|
|
ORDER BY $sort";
|
|
return $DB->get_records_sql($sql, array('userid' => $userid), $limitfrom, $limitnum);
|
|
}
|
|
|
|
/**
|
|
* Issues a certificate to a user.
|
|
*
|
|
* @param int $certificateid The ID of the certificate
|
|
* @param int $userid The ID of the user to issue the certificate to
|
|
* @return int The ID of the issue
|
|
*/
|
|
public static function issue_certificate($certificateid, $userid) {
|
|
global $DB;
|
|
|
|
$issue = new \stdClass();
|
|
$issue->userid = $userid;
|
|
$issue->htmlcertid = $certificateid;
|
|
$issue->code = self::generate_code();
|
|
$issue->emailed = 0;
|
|
$issue->timecreated = time();
|
|
|
|
// Insert the record into the database.
|
|
return $DB->insert_record('htmlcert_issues', $issue);
|
|
}
|
|
|
|
/**
|
|
* Generates a 10-digit code of random letters and numbers.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function generate_code() {
|
|
global $DB;
|
|
|
|
$uniquecodefound = false;
|
|
$code = random_string(10);
|
|
while (!$uniquecodefound) {
|
|
if (!$DB->record_exists('htmlcert_issues', array('code' => $code))) {
|
|
$uniquecodefound = true;
|
|
} else {
|
|
$code = random_string(10);
|
|
}
|
|
}
|
|
|
|
return $code;
|
|
}
|
|
}
|