AutorÃa | Ultima modificación | Ver Log |
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file manages the public functions of this module
*
* @package mod_custommailing
* @author jeanfrancois@cblue.be,olivier@cblue.be
* @copyright 2021 CBlue SPRL
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core\notification;
use mod_custommailing\Mailing;
use mod_custommailing\MailingLog;
define('MAILING_MODE_NONE', 0);
define('MAILING_MODE_FIRSTLAUNCH', 1);
define('MAILING_MODE_REGISTRATION', 2);
define('MAILING_MODE_COMPLETE', 3);
define('MAILING_MODE_DAYSFROMINSCRIPTIONDATE', 4);
define('MAILING_MODE_DAYSFROMLASTCONNECTION', 5);
define('MAILING_MODE_DAYSFROMFIRSTLAUNCH', 6);
define('MAILING_MODE_DAYSFROMLASTLAUNCH', 7);
define('MAILING_MODE_SEND_CERTIFICATE', 8);
define('MAILING_STATUS_DISABLED', 0);
define('MAILING_STATUS_ENABLED', 1);
define('MAILING_LOG_IDLE', 0);
define('MAILING_LOG_PROCESSING', 1);
define('MAILING_LOG_SENT', 2);
define('MAILING_LOG_FAILED', 3);
define('MAILING_SOURCE_MODULE', 1);
define('MAILING_SOURCE_COURSE', 2);
define('MAILING_SOURCE_CERT', 3);
/**
* @param $custommailing
* @return bool|int
* @throws coding_exception
* @throws dml_exception
*/
function custommailing_add_instance($custommailing) {
global $CFG, $DB;
$custommailing->timecreated = time();
$custommailing->timemodified = time();
// Check if course has completion enabled, and enable it if not (and user has permission to do so)
$course = $DB->get_record('course', ['id' => $custommailing->course]);
if (empty($course->enablecompletion)) {
if (empty($CFG->enablecompletion)) {
// Completion tracking is disabled in Moodle
notification::error(get_string('coursecompletionnotenabled', 'custommailing'));
} else {
// Completion tracking is enabled in Moodle
if (has_capability('moodle/course:update', context_course::instance($course->id))) {
$data = ['id' => $course->id, 'enablecompletion' => '1'];
$DB->update_record('course', $data);
rebuild_course_cache($course->id);
notification::warning(get_string('coursecompletionenabled', 'custommailing'));
} else {
notification::error(get_string('coursecompletionnotenabled', 'custommailing'));
}
}
}
return $DB->insert_record('custommailing', $custommailing);
}
/**
* @param $custommailing
* @return bool
* @throws dml_exception
*/
function custommailing_update_instance($custommailing) {
global $DB;
$custommailing->timemodified = time();
$custommailing->id = $custommailing->instance;
return $DB->update_record('custommailing', $custommailing);
}
/**
* @param $id
* @return bool
* @throws dml_exception
*/
function custommailing_delete_instance($id) {
global $DB;
if (!$custommailing = $DB->get_record('custommailing', ['id' => $id])) {
return false;
}
$result = true;
// Delete any dependent mailing here.
Mailing::deleteAll($custommailing->id);
if (!$DB->delete_records('custommailing', ['id' => $custommailing->id])) {
$result = false;
}
return $result;
}
/**
* @param $feature
* @return bool|null
*/
function custommailing_supports($feature) {
switch($feature) {
case FEATURE_GRADE_HAS_GRADE:
return false;
case FEATURE_GRADE_OUTCOMES:
return false;
case FEATURE_ADVANCED_GRADING:
return false;
case FEATURE_CONTROLS_GRADE_VISIBILITY:
return false;
case FEATURE_COMPLETION_TRACKS_VIEWS:
return false;
case FEATURE_COMPLETION_HAS_RULES:
return false;
case FEATURE_NO_VIEW_LINK:
return false;
case FEATURE_IDNUMBER:
return true;
case FEATURE_GROUPS:
return false;
case FEATURE_GROUPINGS:
return false;
case FEATURE_MOD_INTRO:
return false;
case FEATURE_MODEDIT_DEFAULT_COMPLETION:
return false;
case FEATURE_COMMENT:
return false;
case FEATURE_RATE:
return false;
case FEATURE_BACKUP_MOODLE2:
return true;
case FEATURE_SHOW_DESCRIPTION:
return false;
case FEATURE_USES_QUESTIONS:
return false;
default:
return false;
}
}
/**
* @param mixed $only [false for all OR modname (scorm, quiz, etc...)]
* @return array
* @throws moodle_exception
*/
function custommailing_get_activities ($only= false) {
global $COURSE, $PAGE;
$course_module_context = $PAGE->context;
$activities = [];
foreach ($modinfo = get_fast_modinfo($COURSE)->get_cms() as $cm) {
if ($cm->id != $course_module_context->instanceid) {
if (!$only || $cm->modname == $only) {
$activities[(int) $cm->id] = format_string($cm->name);
}
}
}
return $activities;
}
/**
* @param int $courseid
* @return array
* @throws dml_exception
*/
function custommailing_getcustomcertsfromcourse($courseid)
{
global $DB;
$certs = [];
$result = $DB->get_records('customcert', ['course' => $courseid]);
foreach ($result as $cert) {
$certs[(int) $cert->id] = format_string($cert->name);
}
return $certs;
}
/**
* @param int $customcertmoduleid
* @return false|mixed|stdClass
* @throws dml_exception
*/
function custommailing_getCmFromCustomcertInstance($customcertmoduleid)
{
global $DB;
$module = $DB->get_record('modules', ['name' => 'customcert']);
if (!empty($module->id)) {
return $DB->get_record('course_modules', ['instance' => $customcertmoduleid, 'module' => $module->id]);
} else {
return false;
}
}
/**
* @param int $customcertid
* @return false|mixed|stdClass
* @throws dml_exception
*/
function custommailing_getCustomcert($customcertid)
{
global $DB;
return $DB->get_record('customcert', ['id' => $customcertid]);
}
/**
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
function custommailing_logs_generate()
{
global $DB;
$mailings = Mailing::getAllToSend();
foreach ($mailings as $mailing) {
$sql = custommailing_getsql($mailing);
if (!empty($sql['sql']) && !empty($sql['params'])) {
$users = $DB->get_records_sql($sql['sql'], $sql['params']);
if (is_array($users)) {
foreach ($users as $user) {
if (validate_email($user->email) && !$DB->get_record('custommailing_logs', ['custommailingmailingid' => $mailing->id, 'emailtouserid' => $user->id])) {
$record = new stdClass();
$record->custommailingmailingid = (int) $mailing->id;
$record->emailtouserid = (int) $user->id;
$record->emailstatus = MAILING_LOG_PROCESSING;
$record->timecreated = time();
MailingLog::create($record);
}
}
}
}
}
}
/**
* @param object $mailing
* @return false|string
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
function custommailing_getsql($mailing)
{
$sql = false;
$params = [];
$config = get_config('custommailing');
if (!empty($config->debugmode)) {
$delay_range = 'MINUTE';
} else {
$delay_range = 'DAY';
}
// target module completion
if (!empty($mailing->targetmoduleid)) {
if (!empty($mailing->targetmodulestatus)) {
$sql_where = " AND (cmc.completionstate IN (0,3) OR cmc.completionstate IS NULL)";
} else {
$sql_where = " AND cmc.completionstate IN (1,2)";
}
} else {
$sql_where = '';
}
// mailing modes
if ($mailing->mailingmode == MAILING_MODE_FIRSTLAUNCH && !empty($mailing->targetmoduleid)) {
$sql = "SELECT DISTINCT u.*
FROM {user} u
JOIN {logstore_standard_log} lsl ON lsl.userid = u.id AND lsl.contextlevel = 70 AND lsl.contextinstanceid = :targetmoduleid AND lsl.action = 'viewed'
";
$params['targetmoduleid'] = $mailing->targetmoduleid;
} elseif ($mailing->mailingmode == MAILING_MODE_REGISTRATION && !empty($mailing->courseid)) {
// retroactive mode
if (!$mailing->retroactive) {
$sql_retro = " AND ue.timecreated >= :timecreated AND (ue.timestart = 0 OR ue.timestart >= :timestart) AND (ue.timeend = 0 OR ue.timeend >= :timeend)";
$params['timecreated'] = $mailing->timecreated;
$params['timestart'] = $mailing->timecreated;
$params['timeend'] = $mailing->timecreated;
} else {
$sql_retro = '';
}
$sql = "SELECT DISTINCT u.*
FROM {user} u
JOIN {user_enrolments} ue ON ue.userid = u.id
JOIN {enrol} e ON e.id = ue.enrolid
WHERE e.courseid = :courseid $sql_retro
";
$params['courseid'] = $mailing->courseid;
} elseif ($mailing->mailingmode == MAILING_MODE_COMPLETE && !empty($mailing->targetmoduleid)) {
$sql = "SELECT DISTINCT u.*
FROM {user} u
JOIN {course_modules_completion} cmc ON cmc.userid = u.id AND cmc.coursemoduleid = :targetmoduleid
";
$params['targetmoduleid'] = $mailing->targetmoduleid;
} elseif ($mailing->mailingmode == MAILING_MODE_DAYSFROMINSCRIPTIONDATE && !empty($mailing->mailingdelay)) {
// retroactive mode
if (!$mailing->retroactive) {
$sql_retro = " AND ue.timecreated >= :timecreated AND (ue.timestart = 0 OR ue.timestart >= :timestart) AND (ue.timeend = 0 OR ue.timeend >= :timeend)";
$params['timecreated'] = $mailing->timecreated;
$params['timestart'] = $mailing->timecreated;
$params['timeend'] = $mailing->timecreated;
} else {
$sql_retro = '';
}
$start = new \DateTime();
$interval_duration = "P" . $mailing->mailingdelay . "D";
if ($delay_range == 'MINUTE') {
$interval_duration = "PT" . $mailing->mailingdelay . "M";
}
$start->sub(new DateInterval($interval_duration));
$sql = "SELECT DISTINCT u.*
FROM {user} u
JOIN {user_enrolments} ue ON ue.userid = u.id
JOIN {enrol} e ON e.id = ue.enrolid
WHERE e.courseid = :courseid AND ue.timestart < " . $start->getTimestamp() . " $sql_retro
";
$params['courseid'] = $mailing->courseid;
} elseif ($mailing->mailingmode == MAILING_MODE_DAYSFROMLASTCONNECTION && !empty($mailing->courseid)) {
// retroactive mode
if (!$mailing->retroactive) {
$sql_retro = " AND lsl.timecreated >= :timecreated1";
$params['timecreated1'] = $mailing->timecreated;
} else {
$sql_retro = '';
}
$start = new \DateTime();
$interval_duration = "P" . $mailing->mailingdelay . "D";
if ($delay_range == 'MINUTE') {
$interval_duration = "PT" . $mailing->mailingdelay . "M";
}
$start->sub(new DateInterval($interval_duration));
$sql = "SELECT DISTINCT u.*
FROM {user} u
JOIN {course} c ON c.id = :courseid
JOIN {logstore_standard_log} lsl ON lsl.userid = u.id AND lsl.contextlevel = 50 AND lsl.action = 'viewed' AND lsl.courseid = c.id
WHERE lsl.timecreated < :timecreated2 $sql_retro
";
$params['courseid'] = $mailing->courseid;
$params['timecreated2'] = $start->getTimestamp();
} elseif ($mailing->mailingmode == MAILING_MODE_DAYSFROMFIRSTLAUNCH && !empty($mailing->targetmoduleid) && !empty($mailing->mailingdelay)) {
// retroactive mode
$join = "JOIN {user_enrolments} ue ON ue.userid = u.id
JOIN {enrol} e ON e.id = ue.enrolid
JOIN {course} c ON c.id = e.courseid";
$sql_where .= " AND c.id = :courseid ";
$params['courseid'] = $mailing->courseid;
if (!$mailing->retroactive) {
$sql_where .= " AND ue.timecreated >= :timecreated1 AND (ue.timestart = 0 OR ue.timestart >= :timestart) AND (ue.timeend = 0 OR ue.timeend >= :timeend)";
$params['timecreated1'] = $mailing->timecreated;
$params['timestart'] = $mailing->timecreated;
$params['timeend'] = $mailing->timecreated;
}
$start = new \DateTime();
$interval_duration = "P" . $mailing->mailingdelay . "D";
if ($delay_range == 'MINUTE') {
$interval_duration = "PT" . $mailing->mailingdelay . "M";
}
$start->sub(new DateInterval($interval_duration));
//ToDo : other modules than scorm
if (empty($mailing->targetmodulestatus)) {
$sql = "SELECT DISTINCT u.*
FROM {user} u
$join
JOIN {logstore_standard_log} lsl ON lsl.userid = u.id AND lsl.contextlevel = 70 AND lsl.contextinstanceid = :targetmoduleid AND lsl.action = 'launched' AND lsl.target = 'sco'
LEFT JOIN {course_modules_completion} cmc ON cmc.userid = u.id AND cmc.coursemoduleid = :coursemoduleid
WHERE lsl.timecreated < :timecreated $sql_where
";
} else {
$sql = "SELECT DISTINCT u.*
FROM {user} u
$join
LEFT JOIN {logstore_standard_log} lsl ON lsl.userid = u.id AND lsl.contextlevel = 70 AND lsl.contextinstanceid = :targetmoduleid AND lsl.action = 'launched' AND lsl.target = 'sco'
LEFT JOIN {course_modules_completion} cmc ON cmc.userid = u.id AND cmc.coursemoduleid = :coursemoduleid
WHERE (lsl.timecreated < :timecreated OR lsl.timecreated IS NULL) $sql_where
";
}
$params['targetmoduleid'] = $mailing->targetmoduleid;
$params['coursemoduleid'] = $mailing->targetmoduleid;
$params['timecreated'] = $start->getTimestamp();
} elseif ($mailing->mailingmode == MAILING_MODE_DAYSFROMLASTLAUNCH && !empty($mailing->targetmoduleid) && !empty($mailing->mailingdelay)) {
// retroactive mode
if (!$mailing->retroactive) {
$join_retro = " JOIN {user_enrolments} ue ON ue.userid = u.id
JOIN {enrol} e ON e.id = ue.enrolid
JOIN {course} c ON c.id = e.courseid ";
$sql_where .= " c.id = :courseid AND ue.timecreated >= :timecreated AND (ue.timestart = 0 OR ue.timestart >= :timestart) AND (ue.timeend = 0 OR ue.timeend >= :timeend)";
$params['courseid'] = $mailing->courseid;
$params['timecreated'] = $mailing->timecreated;
$params['timestart'] = $mailing->timecreated;
$params['timeend'] = $mailing->timecreated;
} else {
$join_retro = '';
}
$start = new \DateTime();
$interval_duration = "P" . $mailing->mailingdelay . "D";
if ($delay_range == 'MINUTE') {
$interval_duration = "PT" . $mailing->mailingdelay . "M";
}
$start->sub(new DateInterval($interval_duration));
//ToDo : other modules than scorm
$sql = "SELECT DISTINCT u.*
FROM {user} u
$join_retro
JOIN {logstore_standard_log} lsl ON lsl.userid = u.id AND lsl.contextlevel = 70 AND lsl.contextinstanceid = :contextinstanceid AND lsl.action = 'launched' AND lsl.target = 'sco'
LEFT JOIN {course_modules_completion} cmc ON cmc.userid = u.id AND cmc.coursemoduleid = :coursemoduleid
WHERE lsl.timecreated < :timecreated $sql_where
";
$params['contextinstanceid'] = $mailing->targetmoduleid;
$params['coursemoduleid'] = $mailing->targetmoduleid;
$params['timecreated'] = $start->getTimestamp();
} elseif ($mailing->mailingmode == MAILING_MODE_SEND_CERTIFICATE && !empty($mailing->customcertmoduleid)) {
custommailing_certifications($mailing->customcertmoduleid, $mailing->courseid);
// retroactive mode
if (!$mailing->retroactive) {
$join_retro = " JOIN {user_enrolments} ue ON ue.userid = u.id
JOIN {enrol} e ON e.id = ue.enrolid
JOIN {course} c ON c.id = e.courseid ";
$sql_where = " WHERE c.id = :courseid AND ue.timecreated >= :timecreated1 AND (ue.timestart = 0 OR ue.timestart >= :timestart) AND (ue.timeend = 0 OR ue.timeend >= :timeend)";
$params['courseid'] = $mailing->courseid;
$params['timecreated1'] = $mailing->timecreated;
$params['timestart'] = $mailing->timecreated;
$params['timeend'] = $mailing->timecreated;
} else {
$join_retro = '';
$sql_where = '';
}
$sql = "SELECT DISTINCT u.*
FROM {user} u
$join_retro
JOIN {customcert_issues} ci ON ci.userid = u.id AND ci.customcertid = $mailing->customcertmoduleid
$sql_where
";
}
$return = [
'sql' => $sql,
'params' => $params
];
return $return;
}
/**
* Process custommailing_logs MAILING_LOG_SENT records
* Send email to each user
*
* @throws dml_exception
*/
function custommailing_crontask() {
global $DB;
custommailing_logs_generate();
$ids_to_update = [];
$sql = "SELECT u.*, u.id as userid, rm.mailingsubject, rm.mailingcontent, rl.id as logid, rm.customcertmoduleid
FROM {user} u
JOIN {custommailing_logs} rl ON rl.emailtouserid = u.id
JOIN {custommailing_mailing} rm ON rm.id = rl.custommailingmailingid
WHERE rl.emailstatus < :mailing_log_sent";
$logs = $DB->get_recordset_sql($sql, ['mailing_log_sent' => MAILING_LOG_SENT]);
foreach ($logs as $log) {
if (!empty($log->customcertmoduleid)) {
$attachment = custommailing_getcertificate($log->userid, $log->customcertmoduleid);
} else {
$attachment = new stdClass();
$attachment->file = '';
$attachment->filename = '';
}
$log->mailingcontent = str_replace(['%firstname%', '%lastname%'], [$log->firstname, $log->lastname], $log->mailingcontent);
if (email_to_user($log, core_user::get_support_user(), $log->mailingsubject, strip_tags($log->mailingcontent), $log->mailingcontent, $attachment->file, $attachment->filename)) {
$ids_to_update[] = $log->logid;
}
}
$logs->close();
// Set emailstatus to MAILING_LOG_SENT on each sended email
if (is_array($ids_to_update) && count($ids_to_update)) {
list($insql, $sqlparams) = $DB->get_in_or_equal($ids_to_update, SQL_PARAMS_NAMED);
$sqlparams['mailing_log_sent'] = MAILING_LOG_SENT;
$DB->execute("UPDATE {custommailing_logs} SET emailstatus = :mailing_log_sent WHERE id $insql", $sqlparams);
}
}
/**
* get certificate (REQUIRE mod/customcert)
*
* @param int $userid
* @param int $customcertid
* @return stdClass
* @throws dml_exception
*/
function custommailing_getcertificate($userid, $customcertid) {
global $DB;
$sql = "SELECT c.*, ct.id as templateid, ct.name as templatename, ct.contextid, co.id as courseid,
co.fullname as coursefullname, co.shortname as courseshortname
FROM {customcert} c
JOIN {customcert_templates} ct ON c.templateid = ct.id
JOIN {course} co ON c.course = co.id
JOIN {customcert_issues} ci ON ci.customcertid = c.id
WHERE ci.userid = :userid AND c.id = :certid";
$customcert = $DB->get_record_sql($sql, ['userid' => $userid, 'certid' => $customcertid]);
$template = new \stdClass();
$template->id = $customcert->templateid;
$template->name = $customcert->templatename;
$template->contextid = $customcert->contextid;
$template = new \mod_customcert\template($template);
$filecontents = $template->generate_pdf(false, $userid, true);
// Set the name of the file we are going to send.
$filename = $customcert->courseshortname . '_' . $customcert->name;
$filename = \core_text::entities_to_utf8($filename);
$filename = strip_tags($filename);
$filename = rtrim($filename, '.');
$filename = str_replace('&', '_', $filename) . '.pdf';
// Create the file we will be sending.
$tempdir = make_temp_directory('certificate/attachment');
$tempfile = $tempdir . '/' . md5(microtime() . $userid) . '.pdf';
file_put_contents($tempfile, $filecontents);
$attach = new stdClass();
$attach->file = $tempfile;
$attach->filename = $filename;
return $attach;
}
/**
* @param int $customcertid
* @param int $courseid
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
function custommailing_certifications($customcertid, $courseid)
{
global $DB;
$sql = "SELECT u.*
FROM {user} u
JOIN {course} c ON c.id = :courseid
JOIN {enrol} e ON e.courseid = c.id
JOIN {user_enrolments} ue ON ue.userid = u.id AND ue.enrolid = e.id";
$users = $DB->get_records_sql($sql, ['courseid' => $courseid]);
foreach ($users as $user) {
custommailing_certification($user->id, $customcertid, $courseid);
}
}
/**
* @param int $userid
* @param int $customcertid
* @param int $courseid
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
function custommailing_certification($userid, $customcertid, $courseid)
{
global $DB;
$sql = "SELECT cm.*, m.name, md.name AS modname
FROM {course_modules} cm
JOIN {modules} md ON md.id = cm.module
JOIN {customcert} m ON m.id = cm.instance
WHERE cm.instance = :cminstance AND md.name = :modulename AND cm.course = :courseid";
$cm = $DB->get_record_sql($sql, ['cminstance' => $customcertid, 'modulename' => 'customcert', 'courseid' => $courseid]);
// $cm = get_coursemodule_from_id('customcert', $cmid, $courseid, false, MUST_EXIST);
$modinfo = get_fast_modinfo($courseid);
$cminfo = $modinfo->get_cm($cm->id);
$ainfomod = new \core_availability\info_module($cminfo);
if ($ainfomod->is_available($availabilityinfo, false, $userid)) {
$customcertissue = new stdClass();
$customcertissue->customcertid = $customcertid;
$customcertissue->userid = $userid;
$customcertissue->code = \mod_customcert\certificate::generate_code();
$customcertissue->timecreated = time();
if (!$DB->record_exists('customcert_issues', ['userid' => $userid, 'customcertid' => $customcertid])) {
$DB->insert_record('customcert_issues', $customcertissue);
}
}
}