Ejemplo n.º 1
3
 /**
  * Reset contents of all database tables to initial values, reset caches, etc.
  *
  * Note: this is relatively slow (cca 2 seconds for pg and 7 for mysql) - please use with care!
  *
  * @static
  * @param bool $detectchanges
  *      true  - changes in global state and database are reported as errors
  *      false - no errors reported
  *      null  - only critical problems are reported as errors
  * @return void
  */
 public static function reset_all_data($detectchanges = false)
 {
     global $DB, $CFG, $USER, $SITE, $COURSE, $PAGE, $OUTPUT, $SESSION;
     // Stop any message redirection.
     phpunit_util::stop_message_redirection();
     // Stop any message redirection.
     phpunit_util::stop_phpmailer_redirection();
     // Stop any message redirection.
     phpunit_util::stop_event_redirection();
     // We used to call gc_collect_cycles here to ensure desctructors were called between tests.
     // This accounted for 25% of the total time running phpunit - so we removed it.
     // Show any unhandled debugging messages, the runbare() could already reset it.
     self::display_debugging_messages();
     self::reset_debugging();
     // reset global $DB in case somebody mocked it
     $DB = self::get_global_backup('DB');
     if ($DB->is_transaction_started()) {
         // we can not reset inside transaction
         $DB->force_transaction_rollback();
     }
     $resetdb = self::reset_database();
     $warnings = array();
     if ($detectchanges === true) {
         if ($resetdb) {
             $warnings[] = 'Warning: unexpected database modification, resetting DB state';
         }
         $oldcfg = self::get_global_backup('CFG');
         $oldsite = self::get_global_backup('SITE');
         foreach ($CFG as $k => $v) {
             if (!property_exists($oldcfg, $k)) {
                 $warnings[] = 'Warning: unexpected new $CFG->' . $k . ' value';
             } else {
                 if ($oldcfg->{$k} !== $CFG->{$k}) {
                     $warnings[] = 'Warning: unexpected change of $CFG->' . $k . ' value';
                 }
             }
             unset($oldcfg->{$k});
         }
         if ($oldcfg) {
             foreach ($oldcfg as $k => $v) {
                 $warnings[] = 'Warning: unexpected removal of $CFG->' . $k;
             }
         }
         if ($USER->id != 0) {
             $warnings[] = 'Warning: unexpected change of $USER';
         }
         if ($COURSE->id != $oldsite->id) {
             $warnings[] = 'Warning: unexpected change of $COURSE';
         }
     }
     if (ini_get('max_execution_time') != 0) {
         // This is special warning for all resets because we do not want any
         // libraries to mess with timeouts unintentionally.
         // Our PHPUnit integration is not supposed to change it either.
         if ($detectchanges !== false) {
             $warnings[] = 'Warning: max_execution_time was changed to ' . ini_get('max_execution_time');
         }
         set_time_limit(0);
     }
     // restore original globals
     $_SERVER = self::get_global_backup('_SERVER');
     $CFG = self::get_global_backup('CFG');
     $SITE = self::get_global_backup('SITE');
     $_GET = array();
     $_POST = array();
     $_FILES = array();
     $_REQUEST = array();
     $COURSE = $SITE;
     // reinitialise following globals
     $OUTPUT = new bootstrap_renderer();
     $PAGE = new moodle_page();
     $FULLME = null;
     $ME = null;
     $SCRIPT = null;
     // Empty sessison and set fresh new not-logged-in user.
     \core\session\manager::init_empty_session();
     // reset all static caches
     \core\event\manager::phpunit_reset();
     accesslib_clear_all_caches(true);
     get_string_manager()->reset_caches(true);
     reset_text_filters_cache(true);
     events_get_handlers('reset');
     core_text::reset_caches();
     get_message_processors(false, true);
     filter_manager::reset_caches();
     // Reset internal users.
     core_user::reset_internal_users();
     //TODO MDL-25290: add more resets here and probably refactor them to new core function
     // Reset course and module caches.
     if (class_exists('format_base')) {
         // If file containing class is not loaded, there is no cache there anyway.
         format_base::reset_course_cache(0);
     }
     get_fast_modinfo(0, 0, true);
     // Reset other singletons.
     if (class_exists('core_plugin_manager')) {
         core_plugin_manager::reset_caches(true);
     }
     if (class_exists('\\core\\update\\checker')) {
         \core\update\checker::reset_caches(true);
     }
     if (class_exists('\\core\\update\\deployer')) {
         \core\update\deployer::reset_caches(true);
     }
     // purge dataroot directory
     self::reset_dataroot();
     // restore original config once more in case resetting of caches changed CFG
     $CFG = self::get_global_backup('CFG');
     // inform data generator
     self::get_data_generator()->reset();
     // fix PHP settings
     error_reporting($CFG->debug);
     // verify db writes just in case something goes wrong in reset
     if (self::$lastdbwrites != $DB->perf_get_writes()) {
         error_log('Unexpected DB writes in phpunit_util::reset_all_data()');
         self::$lastdbwrites = $DB->perf_get_writes();
     }
     if ($warnings) {
         $warnings = implode("\n", $warnings);
         trigger_error($warnings, E_USER_WARNING);
     }
 }
Ejemplo n.º 2
0
/**
 * Helper function for sending notification mails
 *
 * @param string $message The message
 * @param int $level Notification level
 * @return
 */
function local_sandbox_inform_admin($message, $level = SANDBOX_LEVEL_NOTICE)
{
    // Get recipients
    $recipients = get_users_from_config(get_config('local_sandbox', 'notifyonerrors'), 'moodle/site:config');
    // If there are no recipients, don't execute.
    if (!is_array($recipients) || count($recipients) <= 0) {
        return false;
    }
    // If message level is below configured notice level, don't execute
    if ($level < get_config('local_sandbox', 'notifylevel')) {
        return false;
    }
    // Get subject
    if ($level > SANDBOX_LEVEL_WARNING) {
        $subject = get_string('emailsubjecterror', 'local_sandbox');
    } else {
        if ($level > SANDBOX_LEVEL_NOTICE) {
            $subject = get_string('emailsubjectwarning', 'local_sandbox');
        } else {
            $subject = get_string('emailsubjectnotice', 'local_sandbox');
        }
    }
    // Send mail
    foreach ($recipients as $r) {
        // Email the admin directly rather than putting these through the messaging system
        email_to_user($r, core_user::get_support_user(), $subject, $message);
    }
}
Ejemplo n.º 3
0
 /**
  * Generates the message object for a give subscription and event.
  *
  * @param int $subscriptionid Subscription instance
  * @param \stdClass $eventobj Event data
  *
  * @return false|\stdClass message object
  */
 protected function generate_message($subscriptionid, \stdClass $eventobj)
 {
     try {
         $subscription = subscription_manager::get_subscription($subscriptionid);
     } catch (\dml_exception $e) {
         // Race condition, someone deleted the subscription.
         return false;
     }
     $user = \core_user::get_user($subscription->userid);
     $context = \context_user::instance($user->id, IGNORE_MISSING);
     if ($context === false) {
         // User context doesn't exist. Should never happen, nothing to do return.
         return false;
     }
     $template = $subscription->template;
     $template = $this->replace_placeholders($template, $subscription, $eventobj, $context);
     $msgdata = new \stdClass();
     $msgdata->component = 'tool_monitor';
     // Your component name.
     $msgdata->name = 'notification';
     // This is the message name from messages.php.
     $msgdata->userfrom = \core_user::get_noreply_user();
     $msgdata->userto = $user;
     $msgdata->subject = $subscription->get_name($context);
     $msgdata->fullmessage = format_text($template, $subscription->templateformat, array('context' => $context));
     $msgdata->fullmessageformat = $subscription->templateformat;
     $msgdata->fullmessagehtml = format_text($template, $subscription->templateformat, array('context' => $context));
     $msgdata->smallmessage = '';
     $msgdata->notification = 1;
     // This is only set to 0 for personal messages between users.
     return $msgdata;
 }
Ejemplo n.º 4
0
 /**
  * Define the form.
  */
 public function definition()
 {
     global $CFG, $COURSE;
     $mform = $this->_form;
     $choices = array();
     $choices['0'] = get_string('emaildigestoff');
     $choices['1'] = get_string('emaildigestcomplete');
     $choices['2'] = get_string('emaildigestsubjects');
     $mform->addElement('select', 'maildigest', get_string('emaildigest'), $choices);
     $mform->setDefault('maildigest', core_user::get_property_default('maildigest'));
     $mform->addHelpButton('maildigest', 'emaildigest');
     $choices = array();
     $choices['1'] = get_string('autosubscribeyes');
     $choices['0'] = get_string('autosubscribeno');
     $mform->addElement('select', 'autosubscribe', get_string('autosubscribe'), $choices);
     $mform->setDefault('autosubscribe', core_user::get_property_default('autosubscribe'));
     if (!empty($CFG->forum_trackreadposts)) {
         $choices = array();
         $choices['0'] = get_string('trackforumsno');
         $choices['1'] = get_string('trackforumsyes');
         $mform->addElement('select', 'trackforums', get_string('trackforums'), $choices);
         $mform->setDefault('trackforums', core_user::get_property_default('trackforums'));
     }
     // Add some extra hidden fields.
     $mform->addElement('hidden', 'id');
     $mform->setType('id', PARAM_INT);
     $mform->addElement('hidden', 'course', $COURSE->id);
     $mform->setType('course', PARAM_INT);
     $this->add_action_buttons(true, get_string('savechanges'));
 }
Ejemplo n.º 5
0
 public function export_for_template(\renderer_base $output)
 {
     $data = new \stdClass();
     $data->contacts = array();
     $userids = array();
     foreach ($this->contacts as $contact) {
         $contact = new contact($contact);
         $contactdata = $contact->export_for_template($output);
         $userids[$contactdata->userid] = $contactdata->userid;
         // Check if the contact was selected.
         if ($this->contactuserid == $contactdata->userid) {
             $contactdata->selected = true;
         }
         $data->contacts[] = $contactdata;
     }
     // Check if the other user is not part of the contacts. We may be sending a message to someone
     // we have not had a conversation with, so we want to add a new item to the contacts array.
     if ($this->contactuserid && !isset($userids[$this->contactuserid])) {
         $user = \core_user::get_user($this->contactuserid);
         // Set an empty message so that we know we are messaging the user, and not viewing their profile.
         $user->smallmessage = '';
         $user->useridfrom = $user->id;
         $contact = \core_message\helper::create_contact($user);
         $contact = new contact($contact);
         $contactdata = $contact->export_for_template($output);
         $contactdata->selected = true;
         // Put the contact at the front.
         array_unshift($data->contacts, $contactdata);
     }
     return $data;
 }
Ejemplo n.º 6
0
 /**
  * Get popup notifications for the specified users. Nothing is returned if notifications are disabled.
  *
  * @param int $useridto the user id who received the notification
  * @param string $sort the column name to order by including optionally direction
  * @param int $limit limit the number of result returned
  * @param int $offset offset the result set by this amount
  * @return array notification records
  * @throws \moodle_exception
  * @since 3.2
  */
 public static function get_popup_notifications($useridto = 0, $sort = 'DESC', $limit = 0, $offset = 0)
 {
     global $DB, $USER;
     $sort = strtoupper($sort);
     if ($sort != 'DESC' && $sort != 'ASC') {
         throw new \moodle_exception('invalid parameter: sort: must be "DESC" or "ASC"');
     }
     if (empty($useridto)) {
         $useridto = $USER->id;
     }
     $params = ['useridto1' => $useridto, 'useridto2' => $useridto];
     // Is notification enabled ?
     if ($useridto == $USER->id) {
         $disabled = $USER->emailstop;
     } else {
         $user = \core_user::get_user($useridto, "emailstop", MUST_EXIST);
         $disabled = $user->emailstop;
     }
     if ($disabled) {
         // Notifications are disabled, no need to run giant queries.
         return array();
     }
     $sql = "SELECT * FROM (\n                    SELECT concat('r', r.id) as uniqueid, r.id, r.useridfrom, r.useridto,\n                        r.subject, r.fullmessage, r.fullmessageformat,\n                        r.fullmessagehtml, r.smallmessage, r.notification, r.contexturl,\n                        r.contexturlname, r.timecreated, r.timeuserfromdeleted, r.timeusertodeleted,\n                        r.component, r.eventtype, r.timeread\n                    FROM {message_read} r\n                    WHERE r.notification = 1\n                    AND r.id IN (SELECT messageid FROM {message_popup} WHERE isread = 1)\n                    AND r.useridto = :useridto1\n                UNION ALL\n                    SELECT concat('u', u.id) as uniqueid, u.id, u.useridfrom, u.useridto,\n                        u.subject, u.fullmessage, u.fullmessageformat,\n                        u.fullmessagehtml, u.smallmessage, u.notification, u.contexturl,\n                        u.contexturlname, u.timecreated, u.timeuserfromdeleted, u.timeusertodeleted,\n                        u.component, u.eventtype, 0 as timeread\n                    FROM {message} u\n                    WHERE u.notification = 1\n                    AND u.id IN (SELECT messageid FROM {message_popup} WHERE isread = 0)\n                    AND u.useridto = :useridto2\n                ) f ORDER BY timecreated {$sort}, timeread {$sort}, id {$sort}";
     return array_values($DB->get_records_sql($sql, $params, $offset, $limit));
 }
Ejemplo n.º 7
0
 /**
  * Constructor.
  *
  * @param int $currentuserid The current user we are wanting to view messages for
  * @param int $otheruserid The other user we are wanting to view messages for
  * @param array $messages
  */
 public function __construct($currentuserid, $otheruserid, $messages)
 {
     $ufields = 'id, ' . get_all_user_name_fields(true) . ', lastaccess';
     $this->currentuserid = $currentuserid;
     if ($otheruserid) {
         $this->otheruserid = $otheruserid;
         $this->otheruser = \core_user::get_user($otheruserid, $ufields, MUST_EXIST);
     }
     $this->messages = $messages;
 }
Ejemplo n.º 8
0
 /**
  * Extend the form definition after the data has been parsed.
  */
 public function definition_after_data()
 {
     global $CFG, $DB, $OUTPUT;
     $mform = $this->_form;
     // If language does not exist, use site default lang.
     if ($langsel = $mform->getElementValue('lang')) {
         $lang = reset($langsel);
         // Check lang exists.
         if (!get_string_manager()->translation_exists($lang, false)) {
             $langel =& $mform->getElement('lang');
             $langel->setValue(core_user::get_property_default('lang'));
         }
     }
 }
Ejemplo n.º 9
0
 public function test_create_user()
 {
     global $DB, $CFG;
     require_once $CFG->dirroot . '/user/lib.php';
     $this->resetAfterTest(true);
     $generator = $this->getDataGenerator();
     $count = $DB->count_records('user');
     $this->setCurrentTimeStart();
     $user = $generator->create_user();
     $this->assertEquals($count + 1, $DB->count_records('user'));
     $this->assertSame($user->username, core_user::clean_field($user->username, 'username'));
     $this->assertSame($user->email, core_user::clean_field($user->email, 'email'));
     $this->assertSame(AUTH_PASSWORD_NOT_CACHED, $user->password);
     $this->assertNotEmpty($user->firstnamephonetic);
     $this->assertNotEmpty($user->lastnamephonetic);
     $this->assertNotEmpty($user->alternatename);
     $this->assertNotEmpty($user->middlename);
     $this->assertSame('manual', $user->auth);
     $this->assertSame('en', $user->lang);
     $this->assertSame('1', $user->confirmed);
     $this->assertSame('0', $user->deleted);
     $this->assertTimeCurrent($user->timecreated);
     $this->assertSame($user->timecreated, $user->timemodified);
     $this->assertSame('0.0.0.0', $user->lastip);
     $record = array('auth' => 'email', 'firstname' => 'Žluťoučký', 'lastname' => 'Koníček', 'firstnamephonetic' => 'Zhlutyoucky', 'lastnamephonetic' => 'Koniiczek', 'middlename' => 'Hopper', 'alternatename' => 'horse', 'idnumber' => 'abc1', 'mnethostid' => (string) $CFG->mnet_localhost_id, 'username' => 'konic666', 'password' => 'password1', 'email' => '*****@*****.**', 'confirmed' => '1', 'lang' => 'cs', 'maildisplay' => '1', 'mailformat' => '0', 'maildigest' => '1', 'autosubscribe' => '0', 'trackforums' => '0', 'deleted' => '0', 'timecreated' => '666');
     $user = $generator->create_user($record);
     $this->assertEquals($count + 2, $DB->count_records('user'));
     foreach ($record as $k => $v) {
         if ($k === 'password') {
             $this->assertTrue(password_verify($v, $user->password));
         } else {
             $this->assertSame($v, $user->{$k});
         }
     }
     $record = array('firstname' => 'Some', 'lastname' => 'User', 'idnumber' => 'def', 'username' => 'user666', 'email' => '*****@*****.**', 'deleted' => '1');
     $user = $generator->create_user($record);
     $this->assertEquals($count + 3, $DB->count_records('user'));
     $this->assertSame('', $user->idnumber);
     $this->assertSame(md5($record['username']), $user->email);
     $this->assertFalse(context_user::instance($user->id, IGNORE_MISSING));
     // Test generating user with interests.
     $user = $generator->create_user(array('interests' => 'Cats, Dogs'));
     $userdetails = user_get_user_details($user);
     $this->assertSame('Cats, Dogs', $userdetails['interests']);
 }
 /**
  * Send non-submitters message to students.
  *
  * @param string $message
  * @return void
  */
 public function send_message($userid, $subject, $message)
 {
     $eventdata = new stdClass();
     $eventdata->component = 'mod_turnitintooltwo';
     //your component name
     $eventdata->name = 'nonsubmitters';
     //this is the message name from messages.php
     $eventdata->userfrom = \core_user::get_noreply_user();
     $eventdata->userto = $userid;
     $eventdata->subject = $subject;
     $eventdata->fullmessage = $message;
     $eventdata->fullmessageformat = FORMAT_HTML;
     $eventdata->fullmessagehtml = $message;
     $eventdata->smallmessage = '';
     $eventdata->notification = 1;
     //this is only set to 0 for personal messages between users
     message_send($eventdata);
 }
Ejemplo n.º 11
0
/**
 * This function is used to generate and display the log activity graph
 *
 * @global stdClass $CFG
 * @param  stdClass $course course instance
 * @param  int|stdClass    $user id/object of the user whose logs are needed
 * @param  string $typeormode type of logs graph needed (usercourse.png/userday.png) or the mode (today, all).
 * @param  int $date timestamp in GMT (seconds since epoch)
 * @param  string $logreader Log reader.
 * @return void
 */
function report_log_print_graph($course, $user, $typeormode, $date = 0, $logreader = '')
{
    global $CFG, $OUTPUT;
    if (!is_object($user)) {
        $user = core_user::get_user($user);
    }
    $logmanager = get_log_manager();
    $readers = $logmanager->get_readers();
    if (empty($logreader)) {
        $reader = reset($readers);
    } else {
        $reader = $readers[$logreader];
    }
    // If reader is not a sql_internal_table_reader and not legacy store then don't show graph.
    if (!$reader instanceof \core\log\sql_internal_table_reader && !$reader instanceof logstore_legacy\log\store) {
        return array();
    }
    $coursecontext = context_course::instance($course->id);
    $a = new stdClass();
    $a->coursename = format_string($course->shortname, true, array('context' => $coursecontext));
    $a->username = fullname($user, true);
    if ($typeormode == 'today' || $typeormode == 'userday.png') {
        $logs = report_log_usertoday_data($course, $user, $date, $logreader);
        $title = get_string("hitsoncoursetoday", "", $a);
    } else {
        if ($typeormode == 'all' || $typeormode == 'usercourse.png') {
            $logs = report_log_userall_data($course, $user, $logreader);
            $title = get_string("hitsoncourse", "", $a);
        }
    }
    if (!empty($CFG->preferlinegraphs)) {
        $chart = new \core\chart_line();
    } else {
        $chart = new \core\chart_bar();
    }
    $series = new \core\chart_series(get_string("hits"), $logs['series']);
    $chart->add_series($series);
    $chart->set_title($title);
    $chart->set_labels($logs['labels']);
    $yaxis = $chart->get_yaxis(0, true);
    $yaxis->set_label(get_string("hits"));
    $yaxis->set_stepsize(max(1, round(max($logs['series']) / 10)));
    echo $OUTPUT->render($chart);
}
Ejemplo n.º 12
0
 /**
  * Returns the list of badges awarded to a user.
  *
  * @param int $userid       user id
  * @param int $courseid     course id
  * @param int $page         page of records to return
  * @param int $perpage      number of records to return per page
  * @param string  $search   a simple string to search for
  * @param bool $onlypublic  whether to return only public badges
  * @return array array containing warnings and the awarded badges
  * @since  Moodle 3.1
  * @throws moodle_exception
  */
 public static function get_user_badges($userid = 0, $courseid = 0, $page = 0, $perpage = 0, $search = '', $onlypublic = false)
 {
     global $CFG, $USER;
     $warnings = array();
     $params = array('userid' => $userid, 'courseid' => $courseid, 'page' => $page, 'perpage' => $perpage, 'search' => $search, 'onlypublic' => $onlypublic);
     $params = self::validate_parameters(self::get_user_badges_parameters(), $params);
     if (empty($CFG->enablebadges)) {
         throw new moodle_exception('badgesdisabled', 'badges');
     }
     if (empty($CFG->badges_allowcoursebadges) && $params['courseid'] != 0) {
         throw new moodle_exception('coursebadgesdisabled', 'badges');
     }
     // Default value for userid.
     if (empty($params['userid'])) {
         $params['userid'] = $USER->id;
     }
     // Validate the user.
     $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
     core_user::require_active_user($user);
     $usercontext = context_user::instance($user->id);
     self::validate_context($usercontext);
     if ($USER->id != $user->id) {
         require_capability('moodle/badges:viewotherbadges', $usercontext);
         // We are looking other user's badges, we must retrieve only public badges.
         $params['onlypublic'] = true;
     }
     $userbadges = badges_get_user_badges($user->id, $params['courseid'], $params['page'], $params['perpage'], $params['search'], $params['onlypublic']);
     $result = array();
     $result['badges'] = array();
     $result['warnings'] = $warnings;
     foreach ($userbadges as $badge) {
         $context = $badge->type == BADGE_TYPE_SITE ? context_system::instance() : context_course::instance($badge->courseid);
         $badge->badgeurl = moodle_url::make_webservice_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1')->out(false);
         // Return all the information if we are requesting our own badges.
         // Or, if we have permissions for configuring badges in the badge context.
         if ($USER->id == $user->id or has_capability('moodle/badges:configuredetails', $context)) {
             $result['badges'][] = (array) $badge;
         } else {
             $result['badges'][] = array('name' => $badge->name, 'description' => $badge->description, 'badgeurl' => $badge->badgeurl, 'issuername' => $badge->issuername, 'issuerurl' => $badge->issuerurl, 'issuercontact' => $badge->issuercontact, 'uniquehash' => $badge->uniquehash, 'dateissued' => $badge->dateissued, 'dateexpire' => $badge->dateexpire);
         }
     }
     return $result;
 }
Ejemplo n.º 13
0
 public function test_get_user()
 {
     global $CFG;
     $this->resetAfterTest(true);
     // Create user and try fetach it with api.
     $user = $this->getDataGenerator()->create_user();
     $this->assertEquals($user, core_user::get_user($user->id, '*', MUST_EXIST));
     // Test noreply user.
     $CFG->noreplyuserid = null;
     $noreplyuser = core_user::get_noreply_user();
     $this->assertEquals(1, $noreplyuser->emailstop);
     $this->assertFalse(core_user::is_real_user($noreplyuser->id));
     $this->assertEquals($CFG->noreplyaddress, $noreplyuser->email);
     $this->assertEquals(get_string('noreplyname'), $noreplyuser->firstname);
     // Set user as noreply user and make sure noreply propery is set.
     core_user::reset_internal_users();
     $CFG->noreplyuserid = $user->id;
     $noreplyuser = core_user::get_noreply_user();
     $this->assertEquals(1, $noreplyuser->emailstop);
     $this->assertTrue(core_user::is_real_user($noreplyuser->id));
     // Test support user.
     core_user::reset_internal_users();
     $CFG->supportemail = null;
     $CFG->noreplyuserid = null;
     $supportuser = core_user::get_support_user();
     $adminuser = get_admin();
     $this->assertEquals($adminuser, $supportuser);
     $this->assertTrue(core_user::is_real_user($supportuser->id));
     // When supportemail is set.
     core_user::reset_internal_users();
     $CFG->supportemail = '*****@*****.**';
     $supportuser = core_user::get_support_user();
     $this->assertEquals(core_user::SUPPORT_USER, $supportuser->id);
     $this->assertFalse(core_user::is_real_user($supportuser->id));
     // Set user as support user and make sure noreply propery is set.
     core_user::reset_internal_users();
     $CFG->supportuserid = $user->id;
     $supportuser = core_user::get_support_user();
     $this->assertEquals($user, $supportuser);
     $this->assertTrue(core_user::is_real_user($supportuser->id));
 }
Ejemplo n.º 14
0
function activenotification($id){
	global $DB, $USER, $CFG,$COURSE,$PAGE,$OUTPUT;
	//Batch Name
	$batchname=$DB->get_field('facetoface','name',array('id'=>$id));
	//getting batch users
	$batch_users=$DB->get_records_sql("select * from {local_batch_users} where f2fid=$id");
	//getting session details
	$session_details=$DB->get_records_sql("select * from {facetoface_sessions} where facetoface=$id");
	$sessionsingle="<table border='1' style='text-align:center;'><tr><th>Serial</th><th>Startdate</th><th>Enddate</th><th>Classroom</th></tr>";
	$n=1;
	foreach($session_details as $session_detail){
		//session dates
	$startdateunix=$DB->get_field('facetoface_sessions_dates','timestart',array('sessionid'=>$session_detail->id));
	$enddateuinx=$DB->get_field('facetoface_sessions_dates','timefinish',array('sessionid'=>$session_detail->id));
	//converting dates
	$statrtdate=date('d M Y H:i:s',$startdateunix);
	$enddate=date('d M Y H:i:s',$enddateuinx);
	//session room
	$sessionroom=$DB->get_field('facetoface_room','name',array('id'=>$session_detail->roomid));
		$sessionsingle .="<tr><td>$n</td><td>$statrtdate</td><td>$enddate</td><td>$sessionroom</td></tr>";
		$n++;
	}
	// sending email to each users
	foreach($batch_users as $batch_user){
		 $user_active_details=$DB->get_record_sql("select * from {user} where id=$batch_user->userid");
		 // Course Name
		 $coursename=$DB->get_field('course','fullname',array('id'=>$batch_user->courseid));
		  $from = core_user::get_support_user();
		 $subject =get_string('activenotification', 'facetoface');
         $usermail=new stdClass();
         $usermail->fullname=fullname($batch_user->userid);
		 $usermail->batchname=$batchname;
		 $usermail->coursename=$coursename;
		 $usermail->session=$sessionsingle;
        $messagetext=get_string('activenotificationmsg', 'facetoface',$usermail);
        $email=email_to_user($user_active_details,$from,$subject,$messagetext);
		//print_object(email_to_user($user_active_details,$from,$subject,$messagetext));
		
	}
}
Ejemplo n.º 15
0
 /**
  * Run the deletion task.
  *
  * @throws \coding_exception if the module could not be removed.
  */
 public function execute()
 {
     global $CFG;
     require_once $CFG->dirroot . '/course/lib.php';
     // Set the proper user.
     if ($this->get_custom_data()->userid !== $this->get_custom_data()->realuserid) {
         $realuser = \core_user::get_user($this->get_custom_data()->realuserid, '*', MUST_EXIST);
         cron_setup_user($realuser);
         \core\session\manager::loginas($this->get_custom_data()->userid, \context_system::instance(), false);
     } else {
         $user = \core_user::get_user($this->get_custom_data()->userid, '*', MUST_EXIST);
         cron_setup_user($user);
     }
     $cms = $this->get_custom_data()->cms;
     foreach ($cms as $cm) {
         try {
             course_delete_module($cm->id);
         } catch (\Exception $e) {
             throw new \coding_exception("The course module {$cm->id} could not be deleted. {$e->getTraceAsString()}");
         }
     }
 }
 /**
  * Send instructor message to instructors on course.
  *
  * @param array $instructors
  * @param string $message
  * @return void
  */
 public function send_instructor_message($instructors, $message)
 {
     $subject = get_string('receipt_instructor_copy_subject', 'turnitintooltwo');
     $eventdata = new stdClass();
     $eventdata->component = 'mod_turnitintooltwo';
     //your component name
     $eventdata->name = 'submission';
     //this is the message name from messages.php
     $eventdata->userfrom = \core_user::get_noreply_user();
     $eventdata->subject = $subject;
     $eventdata->fullmessage = $message;
     $eventdata->fullmessageformat = FORMAT_HTML;
     $eventdata->fullmessagehtml = $message;
     $eventdata->smallmessage = '';
     $eventdata->notification = 1;
     //this is only set to 0 for personal messages between users
     foreach ($instructors as $instructor) {
         $eventdata->userto = $instructor->id;
         message_send($eventdata);
     }
     unset($instructor);
 }
Ejemplo n.º 17
0
 /**
  * Whether the user can access the document or not.
  *
  * @param int $id The message instance id.
  * @return int
  */
 public function check_access($id)
 {
     global $CFG, $DB, $USER;
     if (!$CFG->messaging) {
         return \core_search\manager::ACCESS_DENIED;
     }
     $message = $DB->get_record('message_read', array('id' => $id));
     if (!$message) {
         return \core_search\manager::ACCESS_DELETED;
     }
     $userfrom = \core_user::get_user($message->useridfrom, 'id, deleted');
     $userto = \core_user::get_user($message->useridto, 'id, deleted');
     if (!$userfrom || !$userto || $userfrom->deleted || $userto->deleted) {
         return \core_search\manager::ACCESS_DELETED;
     }
     if ($USER->id != $userto->id) {
         return \core_search\manager::ACCESS_DENIED;
     }
     if ($message->timeusertodeleted != 0) {
         return \core_search\manager::ACCESS_DELETED;
     }
     return \core_search\manager::ACCESS_GRANTED;
 }
Ejemplo n.º 18
0
/**
 * Inform admins about assignments that still need upgrading.
 */
function mod_assignment_pending_upgrades_notification($count)
{
    $admins = get_admins();
    if (empty($admins)) {
        return;
    }
    $a = new stdClass();
    $a->count = $count;
    $a->docsurl = get_docs_url('Assignment_upgrade_tool');
    foreach ($admins as $admin) {
        $message = new stdClass();
        $message->component = 'moodle';
        $message->name = 'notices';
        $message->userfrom = \core_user::get_noreply_user();
        $message->userto = $admin;
        $message->smallmessage = get_string('pendingupgrades_message_small', 'mod_assignment');
        $message->subject = get_string('pendingupgrades_message_subject', 'mod_assignment');
        $message->fullmessage = get_string('pendingupgrades_message_content', 'mod_assignment', $a);
        $message->fullmessagehtml = get_string('pendingupgrades_message_content', 'mod_assignment', $a);
        $message->fullmessageformat = FORMAT_PLAIN;
        $message->notification = 1;
        message_send($message);
    }
}
Ejemplo n.º 19
0
    throw new moodle_exception('disabled', 'core_message');
}
$PAGE->set_context(null);
require_sesskey();
$action = optional_param('action', null, PARAM_ALPHA);
$response = null;
switch ($action) {
    // Sending a message.
    case 'sendmessage':
        $userid = required_param('userid', PARAM_INT);
        if (empty($userid) || isguestuser($userid) || $userid == $USER->id) {
            // Cannot send messags to self, nobody or a guest.
            throw new coding_exception('Invalid user to send the message to');
        }
        $message = required_param('message', PARAM_RAW);
        $user2 = core_user::get_user($userid);
        // Only attempt to send the message if we have permission to message
        // the recipient.
        if (message_can_post_message($user2, $USER)) {
            $messageid = message_post_message($USER, $user2, $message, FORMAT_MOODLE);
            if (!$messageid) {
                throw new moodle_exception('errorwhilesendingmessage', 'core_message');
            }
        } else {
            throw new moodle_exception('unabletomessageuser', 'core_message');
        }
        $response = array();
        break;
}
if ($response !== null) {
    echo json_encode($response);
Ejemplo n.º 20
0
 // Save custom profile fields data.
 profile_save_data($usernew);
 // Trigger event.
 \core\event\user_updated::create_from_userid($user->id)->trigger();
 // If email was changed and confirmation is required, send confirmation email now to the new address.
 if ($emailchanged && $CFG->emailchangeconfirmation) {
     $tempuser = $DB->get_record('user', array('id' => $user->id), '*', MUST_EXIST);
     $tempuser->email = $usernew->preference_newemail;
     $a = new stdClass();
     $a->url = $CFG->wwwroot . '/user/emailupdate.php?key=' . $usernew->preference_newemailkey . '&id=' . $user->id;
     $a->site = format_string($SITE->fullname, true, array('context' => context_course::instance(SITEID)));
     $a->fullname = fullname($tempuser, true);
     $emailupdatemessage = get_string('emailupdatemessage', 'auth', $a);
     $emailupdatetitle = get_string('emailupdatetitle', 'auth', $a);
     // Email confirmation directly rather than using messaging so they will definitely get an email.
     $supportuser = core_user::get_support_user();
     if (!($mailresults = email_to_user($tempuser, $supportuser, $emailupdatetitle, $emailupdatemessage))) {
         die("could not send email!");
     }
 }
 // Reload from db, we need new full name on this page if we do not redirect.
 $user = $DB->get_record('user', array('id' => $user->id), '*', MUST_EXIST);
 if ($USER->id == $user->id) {
     // Override old $USER session variable if needed.
     foreach ((array) $user as $variable => $value) {
         if ($variable === 'description' or $variable === 'password') {
             // These are not set for security nad perf reasons.
             continue;
         }
         $USER->{$variable} = $value;
     }
Ejemplo n.º 21
0
 /**
  * Combines the review options from a number of different quiz attempts.
  *
  * @param int $quizid quiz instance id
  * @param int $userid user id (empty for current user)
  * @return array of warnings and the review options
  * @since Moodle 3.1
  */
 public static function get_combined_review_options($quizid, $userid = 0)
 {
     global $DB, $USER;
     $warnings = array();
     $params = array('quizid' => $quizid, 'userid' => $userid);
     $params = self::validate_parameters(self::get_combined_review_options_parameters(), $params);
     list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']);
     // Default value for userid.
     if (empty($params['userid'])) {
         $params['userid'] = $USER->id;
     }
     $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
     core_user::require_active_user($user);
     // Extra checks so only users with permissions can view other users attempts.
     if ($USER->id != $user->id) {
         require_capability('mod/quiz:viewreports', $context);
     }
     $attempts = quiz_get_user_attempts($quiz->id, $user->id, 'all', true);
     $result = array();
     $result['someoptions'] = [];
     $result['alloptions'] = [];
     list($someoptions, $alloptions) = quiz_get_combined_reviewoptions($quiz, $attempts);
     foreach (array('someoptions', 'alloptions') as $typeofoption) {
         foreach (${$typeofoption} as $key => $value) {
             $result[$typeofoption][] = array("name" => $key, "value" => !empty($value) ? $value : 0);
         }
     }
     $result['warnings'] = $warnings;
     return $result;
 }
Ejemplo n.º 22
0
    $currentuser = false;
    //if we're looking at someone else's messages we need to lock/remove some UI elements
    $showactionlinks = false;
} else {
    $user1 = $USER;
}
unset($user1id);
$user2 = null;
if (!empty($user2id)) {
    $user2 = core_user::get_user($user2id);
    if (!$user2) {
        print_error('invaliduserid');
    }
}
unset($user2id);
$user2realuser = !empty($user2) && core_user::is_real_user($user2->id);
$showactionlinks = $showactionlinks && $user2realuser;
$systemcontext = context_system::instance();
if ($currentuser === false && !has_capability('moodle/site:readallmessages', $systemcontext)) {
    print_error('accessdenied', 'admin');
}
if (substr($viewing, 0, 7) == MESSAGE_VIEW_COURSE) {
    $courseid = intval(substr($viewing, 7));
    require_login($courseid);
    require_capability('moodle/course:viewparticipants', context_course::instance($courseid));
    $PAGE->set_pagelayout('incourse');
} else {
    $PAGE->set_pagelayout('standard');
    $PAGE->set_context(context_user::instance($user1->id));
}
if (!empty($user1->id) && $user1->id != $USER->id) {
Ejemplo n.º 23
0
 /**
  * Notify student upon successful submission.
  *
  * @param stdClass $submission
  * @return void
  */
 protected function notify_student_submission_receipt(stdClass $submission)
 {
     global $DB, $USER;
     $adminconfig = $this->get_admin_config();
     if (empty($adminconfig->submissionreceipts)) {
         // No need to do anything.
         return;
     }
     if ($submission->userid) {
         $user = $DB->get_record('user', array('id' => $submission->userid), '*', MUST_EXIST);
     } else {
         $user = $USER;
     }
     if ($submission->userid == $USER->id) {
         $this->send_notification(core_user::get_noreply_user(), $user, 'submissionreceipt', 'assign_notification', $submission->timemodified);
     } else {
         $this->send_notification($USER, $user, 'submissionreceiptother', 'assign_notification', $submission->timemodified);
     }
 }
Ejemplo n.º 24
0
 /**
  * Deletes a message
  *
  * @param  int $messageid the message id
  * @param  int $userid the user id of who we want to delete the message for
  * @param  bool $read if is a message read (default to true)
  * @return external_description
  * @throws moodle_exception
  * @since 3.1
  */
 public static function delete_message($messageid, $userid, $read = true)
 {
     global $CFG, $DB;
     // Check if private messaging between users is allowed.
     if (empty($CFG->messaging)) {
         throw new moodle_exception('disabled', 'message');
     }
     // Warnings array, it can be empty at the end but is mandatory.
     $warnings = array();
     // Validate params.
     $params = array('messageid' => $messageid, 'userid' => $userid, 'read' => $read);
     $params = self::validate_parameters(self::delete_message_parameters(), $params);
     // Validate context.
     $context = context_system::instance();
     self::validate_context($context);
     $messagestable = $params['read'] ? 'message_read' : 'message';
     $message = $DB->get_record($messagestable, array('id' => $params['messageid']), '*', MUST_EXIST);
     $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
     core_user::require_active_user($user);
     $status = false;
     if (message_can_delete_message($message, $user->id)) {
         $status = message_delete_message($message, $user->id);
     } else {
         throw new moodle_exception('You do not have permission to delete this message');
     }
     $results = array('status' => $status, 'warnings' => $warnings);
     return $results;
 }
Ejemplo n.º 25
0
/**
 * Notify admin users or admin user of any failed logins (since last notification).
 *
 * Note that this function must be only executed from the cron script
 * It uses the cache_flags system to store temporary records, deleting them
 * by name before finishing
 *
 * @return bool True if executed, false if not
 */
function notify_login_failures()
{
    global $CFG, $DB, $OUTPUT;
    if (empty($CFG->notifyloginfailures)) {
        return false;
    }
    $recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config');
    if (empty($CFG->lastnotifyfailure)) {
        $CFG->lastnotifyfailure = 0;
    }
    // If it has been less than an hour, or if there are no recipients, don't execute.
    if (time() - HOURSECS < $CFG->lastnotifyfailure || !is_array($recip) || count($recip) <= 0) {
        return false;
    }
    // we need to deal with the threshold stuff first.
    if (empty($CFG->notifyloginthreshold)) {
        $CFG->notifyloginthreshold = 10;
        // default to something sensible.
    }
    // Get all the IPs with more than notifyloginthreshold failures since lastnotifyfailure
    // and insert them into the cache_flags temp table
    $sql = "SELECT ip, COUNT(*)\n              FROM {log}\n             WHERE module = 'login' AND action = 'error'\n                   AND time > ?\n          GROUP BY ip\n            HAVING COUNT(*) >= ?";
    $params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
    $rs = $DB->get_recordset_sql($sql, $params);
    foreach ($rs as $iprec) {
        if (!empty($iprec->ip)) {
            set_cache_flag('login_failure_by_ip', $iprec->ip, '1', 0);
        }
    }
    $rs->close();
    // Get all the INFOs with more than notifyloginthreshold failures since lastnotifyfailure
    // and insert them into the cache_flags temp table
    $sql = "SELECT info, count(*)\n              FROM {log}\n             WHERE module = 'login' AND action = 'error'\n                   AND time > ?\n          GROUP BY info\n            HAVING count(*) >= ?";
    $params = array($CFG->lastnotifyfailure, $CFG->notifyloginthreshold);
    $rs = $DB->get_recordset_sql($sql, $params);
    foreach ($rs as $inforec) {
        if (!empty($inforec->info)) {
            set_cache_flag('login_failure_by_info', $inforec->info, '1', 0);
        }
    }
    $rs->close();
    // Now, select all the login error logged records belonging to the ips and infos
    // since lastnotifyfailure, that we have stored in the cache_flags table
    $sql = "SELECT * FROM (\n        SELECT l.*, u.firstname, u.lastname\n              FROM {log} l\n              JOIN {cache_flags} cf ON l.ip = cf.name\n         LEFT JOIN {user} u         ON l.userid = u.id\n             WHERE l.module = 'login' AND l.action = 'error'\n                   AND l.time > ?\n                   AND cf.flagtype = 'login_failure_by_ip'\n        UNION ALL\n            SELECT l.*, u.firstname, u.lastname\n              FROM {log} l\n              JOIN {cache_flags} cf ON l.info = cf.name\n         LEFT JOIN {user} u         ON l.userid = u.id\n             WHERE l.module = 'login' AND l.action = 'error'\n                   AND l.time > ?\n                   AND cf.flagtype = 'login_failure_by_info') t\n        ORDER BY t.time DESC";
    $params = array($CFG->lastnotifyfailure, $CFG->lastnotifyfailure);
    // Init some variables
    $count = 0;
    $messages = '';
    // Iterate over the logs recordset
    $rs = $DB->get_recordset_sql($sql, $params);
    foreach ($rs as $log) {
        $log->time = userdate($log->time);
        $messages .= get_string('notifyloginfailuresmessage', '', $log) . "\n";
        $count++;
    }
    $rs->close();
    // If we have something useful to report.
    if ($count > 0) {
        $site = get_site();
        $subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname));
        // Calculate the complete body of notification (start + messages + end)
        $body = get_string('notifyloginfailuresmessagestart', '', $CFG->wwwroot) . ($CFG->lastnotifyfailure != 0 ? '(' . userdate($CFG->lastnotifyfailure) . ')' : '') . "\n\n" . $messages . "\n\n" . get_string('notifyloginfailuresmessageend', '', $CFG->wwwroot) . "\n\n";
        // For each destination, send mail
        mtrace('Emailing admins about ' . $count . ' failed login attempts');
        foreach ($recip as $admin) {
            //emailing the admins directly rather than putting these through the messaging system
            email_to_user($admin, core_user::get_support_user(), $subject, $body);
        }
    }
    // Update lastnotifyfailure with current time
    set_config('lastnotifyfailure', time());
    // Finally, delete all the temp records we have created in cache_flags
    $DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')");
    return true;
}
Ejemplo n.º 26
0
/**
 * Sends an email containinginformation on how to change your password.
 *
 * @param stdClass $user A {@link $USER} object
 * @return bool Returns true if mail was sent OK and false if there was an error.
 */
function send_password_change_info($user)
{
    global $CFG;
    $site = get_site();
    $supportuser = core_user::get_support_user();
    $systemcontext = context_system::instance();
    $data = new stdClass();
    $data->firstname = $user->firstname;
    $data->lastname = $user->lastname;
    $data->sitename = format_string($site->fullname);
    $data->admin = generate_email_signoff();
    $userauth = get_auth_plugin($user->auth);
    if (!is_enabled_auth($user->auth) or $user->auth == 'nologin') {
        $message = get_string('emailpasswordchangeinfodisabled', '', $data);
        $subject = get_string('emailpasswordchangeinfosubject', '', format_string($site->fullname));
        // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
        return email_to_user($user, $supportuser, $subject, $message);
    }
    if ($userauth->can_change_password() and $userauth->change_password_url()) {
        // We have some external url for password changing.
        $data->link .= $userauth->change_password_url();
    } else {
        // No way to change password, sorry.
        $data->link = '';
    }
    if (!empty($data->link) and has_capability('moodle/user:changeownpassword', $systemcontext, $user->id)) {
        $message = get_string('emailpasswordchangeinfo', '', $data);
        $subject = get_string('emailpasswordchangeinfosubject', '', format_string($site->fullname));
    } else {
        $message = get_string('emailpasswordchangeinfofail', '', $data);
        $subject = get_string('emailpasswordchangeinfosubject', '', format_string($site->fullname));
    }
    // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
    return email_to_user($user, $supportuser, $subject, $message);
}
Ejemplo n.º 27
0
 /**
  * Send welcome email to specified user.
  *
  * @param stdClass $instance
  * @param stdClass $user user record
  * @return void
  */
 protected function email_welcome_message($instance, $user)
 {
     global $CFG, $DB;
     $course = $DB->get_record('course', array('id' => $instance->courseid), '*', MUST_EXIST);
     $context = context_course::instance($course->id);
     $a = new stdClass();
     $a->coursename = format_string($course->fullname, true, array('context' => $context));
     $a->profileurl = "{$CFG->wwwroot}/user/view.php?id={$user->id}&course={$course->id}";
     if (trim($instance->customtext1) !== '') {
         $message = $instance->customtext1;
         $key = array('{$a->coursename}', '{$a->profileurl}', '{$a->fullname}', '{$a->email}');
         $value = array($a->coursename, $a->profileurl, fullname($user), $user->email);
         $message = str_replace($key, $value, $message);
         if (strpos($message, '<') === false) {
             // Plain text only.
             $messagetext = $message;
             $messagehtml = text_to_html($messagetext, null, false, true);
         } else {
             // This is most probably the tag/newline soup known as FORMAT_MOODLE.
             $messagehtml = format_text($message, FORMAT_MOODLE, array('context' => $context, 'para' => false, 'newlines' => true, 'filter' => true));
             $messagetext = html_to_text($messagehtml);
         }
     } else {
         $messagetext = get_string('welcometocoursetext', 'enrol_self', $a);
         $messagehtml = text_to_html($messagetext, null, false, true);
     }
     $subject = get_string('welcometocourse', 'enrol_self', format_string($course->fullname, true, array('context' => $context)));
     $rusers = array();
     if (!empty($CFG->coursecontact)) {
         $croles = explode(',', $CFG->coursecontact);
         list($sort, $sortparams) = users_order_by_sql('u');
         // We only use the first user.
         $i = 0;
         do {
             $rusers = get_role_users($croles[$i], $context, true, '', 'r.sortorder ASC, ' . $sort, null, '', '', '', '', $sortparams);
             $i++;
         } while (empty($rusers) && !empty($croles[$i]));
     }
     if ($rusers) {
         $contact = reset($rusers);
     } else {
         $contact = core_user::get_support_user();
     }
     // Directly emailing welcome message rather than using messaging.
     email_to_user($user, $contact, $subject, $messagetext, $messagehtml);
 }
Ejemplo n.º 28
0
/**
 * Called when a message provider wants to send a message.
 * This functions checks the message recipient's message processor configuration then
 * sends the message to the configured processors
 *
 * Required parameters of the $eventdata object:
 *  component string component name. must exist in message_providers
 *  name string message type name. must exist in message_providers
 *  userfrom object|int the user sending the message
 *  userto object|int the message recipient
 *  subject string the message subject
 *  fullmessage string the full message in a given format
 *  fullmessageformat int the format if the full message (FORMAT_MOODLE, FORMAT_HTML, ..)
 *  fullmessagehtml string the full version (the message processor will choose with one to use)
 *  smallmessage string the small version of the message
 *
 * Optional parameters of the $eventdata object:
 *  notification bool should the message be considered as a notification rather than a personal message
 *  contexturl string if this is a notification then you can specify a url to view the event. For example the forum post the user is being notified of.
 *  contexturlname string the display text for contexturl
 *
 * Note: processor failure is is not reported as false return value,
 *       earlier versions did not do it consistently either.
 *
 * @todo MDL-55449 Drop support for stdClass in Moodle 3.6
 * @category message
 * @param \core\message\message $eventdata information about the message (component, userfrom, userto, ...)
 * @return mixed the integer ID of the new message or false if there was a problem with submitted data
 */
function message_send($eventdata) {
    global $CFG, $DB;

    // TODO MDL-55449 Drop support for stdClass in Moodle 3.6.
    if ($eventdata instanceof \stdClass) {
        if (!isset($eventdata->courseid)) {
            $eventdata->courseid = null;
        }

        debugging('eventdata as \stdClass is deprecated. Please use core\message\message instead.', DEBUG_DEVELOPER);
    }

    //new message ID to return
    $messageid = false;

    // Fetch default (site) preferences
    $defaultpreferences = get_message_output_default_preferences();
    $preferencebase = $eventdata->component.'_'.$eventdata->name;
    // If message provider is disabled then don't do any processing.
    if (!empty($defaultpreferences->{$preferencebase.'_disable'})) {
        return $messageid;
    }

    // By default a message is a notification. Only personal/private messages aren't notifications.
    if (!isset($eventdata->notification)) {
        $eventdata->notification = 1;
    }

    if (!is_object($eventdata->userto)) {
        $eventdata->userto = core_user::get_user($eventdata->userto);
    }
    if (!is_object($eventdata->userfrom)) {
        $eventdata->userfrom = core_user::get_user($eventdata->userfrom);
    }
    if (!$eventdata->userto) {
        debugging('Attempt to send msg to unknown user', DEBUG_NORMAL);
        return false;
    }
    if (!$eventdata->userfrom) {
        debugging('Attempt to send msg from unknown user', DEBUG_NORMAL);
        return false;
    }

    // Verify all necessary data fields are present.
    if (!isset($eventdata->userto->auth) or !isset($eventdata->userto->suspended)
            or !isset($eventdata->userto->deleted) or !isset($eventdata->userto->emailstop)) {

        debugging('Necessary properties missing in userto object, fetching full record', DEBUG_DEVELOPER);
        $eventdata->userto = core_user::get_user($eventdata->userto->id);
    }

    $usertoisrealuser = (core_user::is_real_user($eventdata->userto->id) != false);
    // If recipient is internal user (noreply user), and emailstop is set then don't send any msg.
    if (!$usertoisrealuser && !empty($eventdata->userto->emailstop)) {
        debugging('Attempt to send msg to internal (noreply) user', DEBUG_NORMAL);
        return false;
    }

    //after how long inactive should the user be considered logged off?
    if (isset($CFG->block_online_users_timetosee)) {
        $timetoshowusers = $CFG->block_online_users_timetosee * 60;
    } else {
        $timetoshowusers = 300;//5 minutes
    }

    // Work out if the user is logged in or not
    if (!empty($eventdata->userto->lastaccess) && (time()-$timetoshowusers) < $eventdata->userto->lastaccess) {
        $userstate = 'loggedin';
    } else {
        $userstate = 'loggedoff';
    }

    // Create the message object
    $savemessage = new stdClass();
    $savemessage->courseid          = $eventdata->courseid;
    $savemessage->useridfrom        = $eventdata->userfrom->id;
    $savemessage->useridto          = $eventdata->userto->id;
    $savemessage->subject           = $eventdata->subject;
    $savemessage->fullmessage       = $eventdata->fullmessage;
    $savemessage->fullmessageformat = $eventdata->fullmessageformat;
    $savemessage->fullmessagehtml   = $eventdata->fullmessagehtml;
    $savemessage->smallmessage      = $eventdata->smallmessage;
    $savemessage->notification      = $eventdata->notification;
    $savemessage->eventtype         = $eventdata->name;
    $savemessage->component         = $eventdata->component;

    if (!empty($eventdata->contexturl)) {
        $savemessage->contexturl = (string)$eventdata->contexturl;
    } else {
        $savemessage->contexturl = null;
    }

    if (!empty($eventdata->contexturlname)) {
        $savemessage->contexturlname = (string)$eventdata->contexturlname;
    } else {
        $savemessage->contexturlname = null;
    }

    $savemessage->timecreated = time();

    if (PHPUNIT_TEST and class_exists('phpunit_util')) {
        // Add some more tests to make sure the normal code can actually work.
        $componentdir = core_component::get_component_directory($eventdata->component);
        if (!$componentdir or !is_dir($componentdir)) {
            throw new coding_exception('Invalid component specified in message-send(): '.$eventdata->component);
        }
        if (!file_exists("$componentdir/db/messages.php")) {
            throw new coding_exception("$eventdata->component does not contain db/messages.php necessary for message_send()");
        }
        $messageproviders = null;
        include("$componentdir/db/messages.php");
        if (!isset($messageproviders[$eventdata->name])) {
            throw new coding_exception("Missing messaging defaults for event '$eventdata->name' in '$eventdata->component' messages.php file");
        }
        unset($componentdir);
        unset($messageproviders);
        // Now ask phpunit if it wants to catch this message.
        if (phpunit_util::is_redirecting_messages()) {
            $savemessage->timeread = time();
            $messageid = $DB->insert_record('message_read', $savemessage);
            $message = $DB->get_record('message_read', array('id'=>$messageid));
            phpunit_util::message_sent($message);
            return $messageid;
        }
    }

    // Fetch enabled processors
    $processors = get_message_processors(true);

    // Preset variables
    $processorlist = array();
    // Fill in the array of processors to be used based on default and user preferences
    foreach ($processors as $processor) {
        // Skip adding processors for internal user, if processor doesn't support sending message to internal user.
        if (!$usertoisrealuser && !$processor->object->can_send_to_any_users()) {
            continue;
        }

        // First find out permissions
        $defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted';
        if (isset($defaultpreferences->{$defaultpreference})) {
            $permitted = $defaultpreferences->{$defaultpreference};
        } else {
            // MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
            // exist in the message_provider table (thus there is no default settings for them).
            $preferrormsg = "Could not load preference $defaultpreference. Make sure the component and name you supplied
                    to message_send() are valid.";
            throw new coding_exception($preferrormsg);
        }

        // Find out if user has configured this output
        // Some processors cannot function without settings from the user
        $userisconfigured = $processor->object->is_user_configured($eventdata->userto);

        // DEBUG: notify if we are forcing unconfigured output
        if ($permitted == 'forced' && !$userisconfigured) {
            debugging('Attempt to force message delivery to user who has "'.$processor->name.'" output unconfigured', DEBUG_NORMAL);
        }

        // Populate the list of processors we will be using
        if ($permitted == 'forced' && $userisconfigured) {
            // An admin is forcing users to use this message processor. Use this processor unconditionally.
            $processorlist[] = $processor->name;
        } else if ($permitted == 'permitted' && $userisconfigured && !$eventdata->userto->emailstop) {
            // User has not disabled notifications
            // See if user set any notification preferences, otherwise use site default ones
            $userpreferencename = 'message_provider_'.$preferencebase.'_'.$userstate;
            if ($userpreference = get_user_preferences($userpreferencename, null, $eventdata->userto)) {
                if (in_array($processor->name, explode(',', $userpreference))) {
                    $processorlist[] = $processor->name;
                }
            } else if (isset($defaultpreferences->{$userpreferencename})) {
                if (in_array($processor->name, explode(',', $defaultpreferences->{$userpreferencename}))) {
                    $processorlist[] = $processor->name;
                }
            }
        }
    }

    // Only cache messages, not notifications.
    if (empty($savemessage->notification)) {
        // Cache the timecreated value of the last message between these two users.
        $cache = cache::make('core', 'message_time_last_message_between_users');
        $key = \core_message\helper::get_last_message_time_created_cache_key($savemessage->useridfrom,
            $savemessage->useridto);
        $cache->set($key, $savemessage->timecreated);
    }

    // Store unread message just in case we get a fatal error any time later.
    $savemessage->id = $DB->insert_record('message', $savemessage);
    $eventdata->savedmessageid = $savemessage->id;

    // Let the manager do the sending or buffering when db transaction in progress.
    return \core\message\manager::send_message($eventdata, $savemessage, $processorlist);
}
Ejemplo n.º 29
0
/**
 * Lockout user and send notification email.
 *
 * @param stdClass $user
 */
function login_lock_account($user)
{
    global $CFG;
    if ($user->mnethostid != $CFG->mnet_localhost_id) {
        return;
    }
    if (isguestuser($user)) {
        return;
    }
    if (get_user_preferences('login_lockout_ignored', 0, $user)) {
        // This user can not be locked out.
        return;
    }
    $alreadylockedout = get_user_preferences('login_lockout', 0, $user);
    set_user_preference('login_lockout', time(), $user);
    if ($alreadylockedout == 0) {
        $secret = random_string(15);
        set_user_preference('login_lockout_secret', $secret, $user);
        $oldforcelang = force_current_language($user->lang);
        $site = get_site();
        $supportuser = core_user::get_support_user();
        $data = new stdClass();
        $data->firstname = $user->firstname;
        $data->lastname = $user->lastname;
        $data->username = $user->username;
        $data->sitename = format_string($site->fullname);
        $data->link = $CFG->wwwroot . '/login/unlock_account.php?u=' . $user->id . '&s=' . $secret;
        $data->admin = generate_email_signoff();
        $message = get_string('lockoutemailbody', 'admin', $data);
        $subject = get_string('lockoutemailsubject', 'admin', format_string($site->fullname));
        if ($message) {
            // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
            email_to_user($user, $supportuser, $subject, $message);
        }
        force_current_language($oldforcelang);
    }
}
Ejemplo n.º 30
0
/**
 * Function to be run periodically according to the scheduled task.
 *
 * Finds all posts that have yet to be mailed out, and mails them
 * out to all subscribers as well as other maintance tasks.
 *
 * NOTE: Since 2.7.2 this function is run by scheduled task rather
 * than standard cron.
 *
 * @todo MDL-44734 The function will be split up into seperate tasks.
 */
function forum_cron()
{
    global $CFG, $USER, $DB, $PAGE;
    $site = get_site();
    // The main renderers.
    $htmlout = $PAGE->get_renderer('mod_forum', 'email', 'htmlemail');
    $textout = $PAGE->get_renderer('mod_forum', 'email', 'textemail');
    $htmldigestfullout = $PAGE->get_renderer('mod_forum', 'emaildigestfull', 'htmlemail');
    $textdigestfullout = $PAGE->get_renderer('mod_forum', 'emaildigestfull', 'textemail');
    $htmldigestbasicout = $PAGE->get_renderer('mod_forum', 'emaildigestbasic', 'htmlemail');
    $textdigestbasicout = $PAGE->get_renderer('mod_forum', 'emaildigestbasic', 'textemail');
    // All users that are subscribed to any post that needs sending,
    // please increase $CFG->extramemorylimit on large sites that
    // send notifications to a large number of users.
    $users = array();
    $userscount = 0;
    // Cached user counter - count($users) in PHP is horribly slow!!!
    // Status arrays.
    $mailcount = array();
    $errorcount = array();
    // caches
    $discussions = array();
    $forums = array();
    $courses = array();
    $coursemodules = array();
    $subscribedusers = array();
    $messageinboundhandlers = array();
    // Posts older than 2 days will not be mailed.  This is to avoid the problem where
    // cron has not been running for a long time, and then suddenly people are flooded
    // with mail from the past few weeks or months
    $timenow = time();
    $endtime = $timenow - $CFG->maxeditingtime;
    $starttime = $endtime - 48 * 3600;
    // Two days earlier
    // Get the list of forum subscriptions for per-user per-forum maildigest settings.
    $digestsset = $DB->get_recordset('forum_digests', null, '', 'id, userid, forum, maildigest');
    $digests = array();
    foreach ($digestsset as $thisrow) {
        if (!isset($digests[$thisrow->forum])) {
            $digests[$thisrow->forum] = array();
        }
        $digests[$thisrow->forum][$thisrow->userid] = $thisrow->maildigest;
    }
    $digestsset->close();
    // Create the generic messageinboundgenerator.
    $messageinboundgenerator = new \core\message\inbound\address_manager();
    $messageinboundgenerator->set_handler('\\mod_forum\\message\\inbound\\reply_handler');
    if ($posts = forum_get_unmailed_posts($starttime, $endtime, $timenow)) {
        // Mark them all now as being mailed.  It's unlikely but possible there
        // might be an error later so that a post is NOT actually mailed out,
        // but since mail isn't crucial, we can accept this risk.  Doing it now
        // prevents the risk of duplicated mails, which is a worse problem.
        if (!forum_mark_old_posts_as_mailed($endtime)) {
            mtrace('Errors occurred while trying to mark some posts as being mailed.');
            return false;
            // Don't continue trying to mail them, in case we are in a cron loop
        }
        // checking post validity, and adding users to loop through later
        foreach ($posts as $pid => $post) {
            $discussionid = $post->discussion;
            if (!isset($discussions[$discussionid])) {
                if ($discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
                    $discussions[$discussionid] = $discussion;
                    \mod_forum\subscriptions::fill_subscription_cache($discussion->forum);
                    \mod_forum\subscriptions::fill_discussion_subscription_cache($discussion->forum);
                } else {
                    mtrace('Could not find discussion ' . $discussionid);
                    unset($posts[$pid]);
                    continue;
                }
            }
            $forumid = $discussions[$discussionid]->forum;
            if (!isset($forums[$forumid])) {
                if ($forum = $DB->get_record('forum', array('id' => $forumid))) {
                    $forums[$forumid] = $forum;
                } else {
                    mtrace('Could not find forum ' . $forumid);
                    unset($posts[$pid]);
                    continue;
                }
            }
            $courseid = $forums[$forumid]->course;
            if (!isset($courses[$courseid])) {
                if ($course = $DB->get_record('course', array('id' => $courseid))) {
                    $courses[$courseid] = $course;
                } else {
                    mtrace('Could not find course ' . $courseid);
                    unset($posts[$pid]);
                    continue;
                }
            }
            if (!isset($coursemodules[$forumid])) {
                if ($cm = get_coursemodule_from_instance('forum', $forumid, $courseid)) {
                    $coursemodules[$forumid] = $cm;
                } else {
                    mtrace('Could not find course module for forum ' . $forumid);
                    unset($posts[$pid]);
                    continue;
                }
            }
            // Save the Inbound Message datakey here to reduce DB queries later.
            $messageinboundgenerator->set_data($pid);
            $messageinboundhandlers[$pid] = $messageinboundgenerator->fetch_data_key();
            // Caching subscribed users of each forum.
            if (!isset($subscribedusers[$forumid])) {
                $modcontext = context_module::instance($coursemodules[$forumid]->id);
                if ($subusers = \mod_forum\subscriptions::fetch_subscribed_users($forums[$forumid], 0, $modcontext, 'u.*', true)) {
                    foreach ($subusers as $postuser) {
                        // this user is subscribed to this forum
                        $subscribedusers[$forumid][$postuser->id] = $postuser->id;
                        $userscount++;
                        if ($userscount > FORUM_CRON_USER_CACHE) {
                            // Store minimal user info.
                            $minuser = new stdClass();
                            $minuser->id = $postuser->id;
                            $users[$postuser->id] = $minuser;
                        } else {
                            // Cache full user record.
                            forum_cron_minimise_user_record($postuser);
                            $users[$postuser->id] = $postuser;
                        }
                    }
                    // Release memory.
                    unset($subusers);
                    unset($postuser);
                }
            }
            $mailcount[$pid] = 0;
            $errorcount[$pid] = 0;
        }
    }
    if ($users && $posts) {
        foreach ($users as $userto) {
            // Terminate if processing of any account takes longer than 2 minutes.
            core_php_time_limit::raise(120);
            mtrace('Processing user ' . $userto->id);
            // Init user caches - we keep the cache for one cycle only, otherwise it could consume too much memory.
            if (isset($userto->username)) {
                $userto = clone $userto;
            } else {
                $userto = $DB->get_record('user', array('id' => $userto->id));
                forum_cron_minimise_user_record($userto);
            }
            $userto->viewfullnames = array();
            $userto->canpost = array();
            $userto->markposts = array();
            // Setup this user so that the capabilities are cached, and environment matches receiving user.
            cron_setup_user($userto);
            // Reset the caches.
            foreach ($coursemodules as $forumid => $unused) {
                $coursemodules[$forumid]->cache = new stdClass();
                $coursemodules[$forumid]->cache->caps = array();
                unset($coursemodules[$forumid]->uservisible);
            }
            foreach ($posts as $pid => $post) {
                $discussion = $discussions[$post->discussion];
                $forum = $forums[$discussion->forum];
                $course = $courses[$forum->course];
                $cm =& $coursemodules[$forum->id];
                // Do some checks to see if we can bail out now.
                // Only active enrolled users are in the list of subscribers.
                // This does not necessarily mean that the user is subscribed to the forum or to the discussion though.
                if (!isset($subscribedusers[$forum->id][$userto->id])) {
                    // The user does not subscribe to this forum.
                    continue;
                }
                if (!\mod_forum\subscriptions::is_subscribed($userto->id, $forum, $post->discussion, $coursemodules[$forum->id])) {
                    // The user does not subscribe to this forum, or to this specific discussion.
                    continue;
                }
                if ($subscriptiontime = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $userto->id)) {
                    // Skip posts if the user subscribed to the discussion after it was created.
                    if (isset($subscriptiontime[$post->discussion]) && $subscriptiontime[$post->discussion] > $post->created) {
                        continue;
                    }
                }
                // Don't send email if the forum is Q&A and the user has not posted.
                // Initial topics are still mailed.
                if ($forum->type == 'qanda' && !forum_get_user_posted_time($discussion->id, $userto->id) && $pid != $discussion->firstpost) {
                    mtrace('Did not email ' . $userto->id . ' because user has not posted in discussion');
                    continue;
                }
                // Get info about the sending user.
                if (array_key_exists($post->userid, $users)) {
                    // We might know the user already.
                    $userfrom = $users[$post->userid];
                    if (!isset($userfrom->idnumber)) {
                        // Minimalised user info, fetch full record.
                        $userfrom = $DB->get_record('user', array('id' => $userfrom->id));
                        forum_cron_minimise_user_record($userfrom);
                    }
                } else {
                    if ($userfrom = $DB->get_record('user', array('id' => $post->userid))) {
                        forum_cron_minimise_user_record($userfrom);
                        // Fetch only once if possible, we can add it to user list, it will be skipped anyway.
                        if ($userscount <= FORUM_CRON_USER_CACHE) {
                            $userscount++;
                            $users[$userfrom->id] = $userfrom;
                        }
                    } else {
                        mtrace('Could not find user ' . $post->userid . ', author of post ' . $post->id . '. Unable to send message.');
                        continue;
                    }
                }
                // Note: If we want to check that userto and userfrom are not the same person this is probably the spot to do it.
                // Setup global $COURSE properly - needed for roles and languages.
                cron_setup_user($userto, $course);
                // Fill caches.
                if (!isset($userto->viewfullnames[$forum->id])) {
                    $modcontext = context_module::instance($cm->id);
                    $userto->viewfullnames[$forum->id] = has_capability('moodle/site:viewfullnames', $modcontext);
                }
                if (!isset($userto->canpost[$discussion->id])) {
                    $modcontext = context_module::instance($cm->id);
                    $userto->canpost[$discussion->id] = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
                }
                if (!isset($userfrom->groups[$forum->id])) {
                    if (!isset($userfrom->groups)) {
                        $userfrom->groups = array();
                        if (isset($users[$userfrom->id])) {
                            $users[$userfrom->id]->groups = array();
                        }
                    }
                    $userfrom->groups[$forum->id] = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
                    if (isset($users[$userfrom->id])) {
                        $users[$userfrom->id]->groups[$forum->id] = $userfrom->groups[$forum->id];
                    }
                }
                // Make sure groups allow this user to see this email.
                if ($discussion->groupid > 0 and $groupmode = groups_get_activity_groupmode($cm, $course)) {
                    // Groups are being used.
                    if (!groups_group_exists($discussion->groupid)) {
                        // Can't find group - be safe and don't this message.
                        continue;
                    }
                    if (!groups_is_member($discussion->groupid) and !has_capability('moodle/site:accessallgroups', $modcontext)) {
                        // Do not send posts from other groups when in SEPARATEGROUPS or VISIBLEGROUPS.
                        continue;
                    }
                }
                // Make sure we're allowed to see the post.
                if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
                    mtrace('User ' . $userto->id . ' can not see ' . $post->id . '. Not sending message.');
                    continue;
                }
                // OK so we need to send the email.
                // Does the user want this post in a digest?  If so postpone it for now.
                $maildigest = forum_get_user_maildigest_bulk($digests, $userto, $forum->id);
                if ($maildigest > 0) {
                    // This user wants the mails to be in digest form.
                    $queue = new stdClass();
                    $queue->userid = $userto->id;
                    $queue->discussionid = $discussion->id;
                    $queue->postid = $post->id;
                    $queue->timemodified = $post->created;
                    $DB->insert_record('forum_queue', $queue);
                    continue;
                }
                // Prepare to actually send the post now, and build up the content.
                $cleanforumname = str_replace('"', "'", strip_tags(format_string($forum->name)));
                $userfrom->customheaders = array('List-Id: "' . $cleanforumname . '" ' . generate_email_messageid('moodleforum' . $forum->id), 'List-Help: ' . $CFG->wwwroot . '/mod/forum/view.php?f=' . $forum->id, 'Message-ID: ' . forum_get_email_message_id($post->id, $userto->id), 'X-Course-Id: ' . $course->id, 'X-Course-Name: ' . format_string($course->fullname, true), 'Precedence: Bulk', 'X-Auto-Response-Suppress: All', 'Auto-Submitted: auto-generated');
                $shortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
                // Generate a reply-to address from using the Inbound Message handler.
                $replyaddress = null;
                if ($userto->canpost[$discussion->id] && array_key_exists($post->id, $messageinboundhandlers)) {
                    $messageinboundgenerator->set_data($post->id, $messageinboundhandlers[$post->id]);
                    $replyaddress = $messageinboundgenerator->generate($userto->id);
                }
                if (!isset($userto->canpost[$discussion->id])) {
                    $canreply = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
                } else {
                    $canreply = $userto->canpost[$discussion->id];
                }
                $data = new \mod_forum\output\forum_post_email($course, $cm, $forum, $discussion, $post, $userfrom, $userto, $canreply);
                $userfrom->customheaders[] = sprintf('List-Unsubscribe: <%s>', $data->get_unsubscribediscussionlink());
                if (!isset($userto->viewfullnames[$forum->id])) {
                    $data->viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
                } else {
                    $data->viewfullnames = $userto->viewfullnames[$forum->id];
                }
                // Not all of these variables are used in the default language
                // string but are made available to support custom subjects.
                $a = new stdClass();
                $a->subject = $data->get_subject();
                $a->forumname = $cleanforumname;
                $a->sitefullname = format_string($site->fullname);
                $a->siteshortname = format_string($site->shortname);
                $a->courseidnumber = $data->get_courseidnumber();
                $a->coursefullname = $data->get_coursefullname();
                $a->courseshortname = $data->get_coursename();
                $postsubject = html_to_text(get_string('postmailsubject', 'forum', $a), 0);
                $rootid = forum_get_email_message_id($discussion->firstpost, $userto->id);
                if ($post->parent) {
                    // This post is a reply, so add reply header (RFC 2822).
                    $parentid = forum_get_email_message_id($post->parent, $userto->id);
                    $userfrom->customheaders[] = "In-Reply-To: {$parentid}";
                    // If the post is deeply nested we also reference the parent message id and
                    // the root message id (if different) to aid threading when parts of the email
                    // conversation have been deleted (RFC1036).
                    if ($post->parent != $discussion->firstpost) {
                        $userfrom->customheaders[] = "References: {$rootid} {$parentid}";
                    } else {
                        $userfrom->customheaders[] = "References: {$parentid}";
                    }
                }
                // MS Outlook / Office uses poorly documented and non standard headers, including
                // Thread-Topic which overrides the Subject and shouldn't contain Re: or Fwd: etc.
                $a->subject = $discussion->name;
                $threadtopic = html_to_text(get_string('postmailsubject', 'forum', $a), 0);
                $userfrom->customheaders[] = "Thread-Topic: {$threadtopic}";
                $userfrom->customheaders[] = "Thread-Index: " . substr($rootid, 1, 28);
                // Send the post now!
                mtrace('Sending ', '');
                $eventdata = new \core\message\message();
                $eventdata->courseid = $course->id;
                $eventdata->component = 'mod_forum';
                $eventdata->name = 'posts';
                $eventdata->userfrom = $userfrom;
                $eventdata->userto = $userto;
                $eventdata->subject = $postsubject;
                $eventdata->fullmessage = $textout->render($data);
                $eventdata->fullmessageformat = FORMAT_PLAIN;
                $eventdata->fullmessagehtml = $htmlout->render($data);
                $eventdata->notification = 1;
                $eventdata->replyto = $replyaddress;
                if (!empty($replyaddress)) {
                    // Add extra text to email messages if they can reply back.
                    $textfooter = "\n\n" . get_string('replytopostbyemail', 'mod_forum');
                    $htmlfooter = html_writer::tag('p', get_string('replytopostbyemail', 'mod_forum'));
                    $additionalcontent = array('fullmessage' => array('footer' => $textfooter), 'fullmessagehtml' => array('footer' => $htmlfooter));
                    $eventdata->set_additional_content('email', $additionalcontent);
                }
                $smallmessagestrings = new stdClass();
                $smallmessagestrings->user = fullname($userfrom);
                $smallmessagestrings->forumname = "{$shortname}: " . format_string($forum->name, true) . ": " . $discussion->name;
                $smallmessagestrings->message = $post->message;
                // Make sure strings are in message recipients language.
                $eventdata->smallmessage = get_string_manager()->get_string('smallmessage', 'forum', $smallmessagestrings, $userto->lang);
                $contexturl = new moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id), 'p' . $post->id);
                $eventdata->contexturl = $contexturl->out();
                $eventdata->contexturlname = $discussion->name;
                $mailresult = message_send($eventdata);
                if (!$mailresult) {
                    mtrace("Error: mod/forum/lib.php forum_cron(): Could not send out mail for id {$post->id} to user {$userto->id}" . " ({$userto->email}) .. not trying again.");
                    $errorcount[$post->id]++;
                } else {
                    $mailcount[$post->id]++;
                    // Mark post as read if forum_usermarksread is set off.
                    if (!$CFG->forum_usermarksread) {
                        $userto->markposts[$post->id] = $post->id;
                    }
                }
                mtrace('post ' . $post->id . ': ' . $post->subject);
            }
            // Mark processed posts as read.
            if (get_user_preferences('forum_markasreadonnotification', 1, $userto->id) == 1) {
                forum_tp_mark_posts_read($userto, $userto->markposts);
            }
            unset($userto);
        }
    }
    if ($posts) {
        foreach ($posts as $post) {
            mtrace($mailcount[$post->id] . " users were sent post {$post->id}, '{$post->subject}'");
            if ($errorcount[$post->id]) {
                $DB->set_field('forum_posts', 'mailed', FORUM_MAILED_ERROR, array('id' => $post->id));
            }
        }
    }
    // release some memory
    unset($subscribedusers);
    unset($mailcount);
    unset($errorcount);
    cron_setup_user();
    $sitetimezone = core_date::get_server_timezone();
    // Now see if there are any digest mails waiting to be sent, and if we should send them
    mtrace('Starting digest processing...');
    core_php_time_limit::raise(300);
    // terminate if not able to fetch all digests in 5 minutes
    if (!isset($CFG->digestmailtimelast)) {
        // To catch the first time
        set_config('digestmailtimelast', 0);
    }
    $timenow = time();
    $digesttime = usergetmidnight($timenow, $sitetimezone) + $CFG->digestmailtime * 3600;
    // Delete any really old ones (normally there shouldn't be any)
    $weekago = $timenow - 7 * 24 * 3600;
    $DB->delete_records_select('forum_queue', "timemodified < ?", array($weekago));
    mtrace('Cleaned old digest records');
    if ($CFG->digestmailtimelast < $digesttime and $timenow > $digesttime) {
        mtrace('Sending forum digests: ' . userdate($timenow, '', $sitetimezone));
        $digestposts_rs = $DB->get_recordset_select('forum_queue', "timemodified < ?", array($digesttime));
        if ($digestposts_rs->valid()) {
            // We have work to do
            $usermailcount = 0;
            //caches - reuse the those filled before too
            $discussionposts = array();
            $userdiscussions = array();
            foreach ($digestposts_rs as $digestpost) {
                if (!isset($posts[$digestpost->postid])) {
                    if ($post = $DB->get_record('forum_posts', array('id' => $digestpost->postid))) {
                        $posts[$digestpost->postid] = $post;
                    } else {
                        continue;
                    }
                }
                $discussionid = $digestpost->discussionid;
                if (!isset($discussions[$discussionid])) {
                    if ($discussion = $DB->get_record('forum_discussions', array('id' => $discussionid))) {
                        $discussions[$discussionid] = $discussion;
                    } else {
                        continue;
                    }
                }
                $forumid = $discussions[$discussionid]->forum;
                if (!isset($forums[$forumid])) {
                    if ($forum = $DB->get_record('forum', array('id' => $forumid))) {
                        $forums[$forumid] = $forum;
                    } else {
                        continue;
                    }
                }
                $courseid = $forums[$forumid]->course;
                if (!isset($courses[$courseid])) {
                    if ($course = $DB->get_record('course', array('id' => $courseid))) {
                        $courses[$courseid] = $course;
                    } else {
                        continue;
                    }
                }
                if (!isset($coursemodules[$forumid])) {
                    if ($cm = get_coursemodule_from_instance('forum', $forumid, $courseid)) {
                        $coursemodules[$forumid] = $cm;
                    } else {
                        continue;
                    }
                }
                $userdiscussions[$digestpost->userid][$digestpost->discussionid] = $digestpost->discussionid;
                $discussionposts[$digestpost->discussionid][$digestpost->postid] = $digestpost->postid;
            }
            $digestposts_rs->close();
            /// Finished iteration, let's close the resultset
            // Data collected, start sending out emails to each user
            foreach ($userdiscussions as $userid => $thesediscussions) {
                core_php_time_limit::raise(120);
                // terminate if processing of any account takes longer than 2 minutes
                cron_setup_user();
                mtrace(get_string('processingdigest', 'forum', $userid), '... ');
                // First of all delete all the queue entries for this user
                $DB->delete_records_select('forum_queue', "userid = ? AND timemodified < ?", array($userid, $digesttime));
                // Init user caches - we keep the cache for one cycle only,
                // otherwise it would unnecessarily consume memory.
                if (array_key_exists($userid, $users) and isset($users[$userid]->username)) {
                    $userto = clone $users[$userid];
                } else {
                    $userto = $DB->get_record('user', array('id' => $userid));
                    forum_cron_minimise_user_record($userto);
                }
                $userto->viewfullnames = array();
                $userto->canpost = array();
                $userto->markposts = array();
                // Override the language and timezone of the "current" user, so that
                // mail is customised for the receiver.
                cron_setup_user($userto);
                $postsubject = get_string('digestmailsubject', 'forum', format_string($site->shortname, true));
                $headerdata = new stdClass();
                $headerdata->sitename = format_string($site->fullname, true);
                $headerdata->userprefs = $CFG->wwwroot . '/user/forum.php?id=' . $userid . '&amp;course=' . $site->id;
                $posttext = get_string('digestmailheader', 'forum', $headerdata) . "\n\n";
                $headerdata->userprefs = '<a target="_blank" href="' . $headerdata->userprefs . '">' . get_string('digestmailprefs', 'forum') . '</a>';
                $posthtml = '<p>' . get_string('digestmailheader', 'forum', $headerdata) . '</p>' . '<br /><hr size="1" noshade="noshade" />';
                foreach ($thesediscussions as $discussionid) {
                    core_php_time_limit::raise(120);
                    // to be reset for each post
                    $discussion = $discussions[$discussionid];
                    $forum = $forums[$discussion->forum];
                    $course = $courses[$forum->course];
                    $cm = $coursemodules[$forum->id];
                    //override language
                    cron_setup_user($userto, $course);
                    // Fill caches
                    if (!isset($userto->viewfullnames[$forum->id])) {
                        $modcontext = context_module::instance($cm->id);
                        $userto->viewfullnames[$forum->id] = has_capability('moodle/site:viewfullnames', $modcontext);
                    }
                    if (!isset($userto->canpost[$discussion->id])) {
                        $modcontext = context_module::instance($cm->id);
                        $userto->canpost[$discussion->id] = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
                    }
                    $strforums = get_string('forums', 'forum');
                    $canunsubscribe = !\mod_forum\subscriptions::is_forcesubscribed($forum);
                    $canreply = $userto->canpost[$discussion->id];
                    $shortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
                    $posttext .= "\n \n";
                    $posttext .= '=====================================================================';
                    $posttext .= "\n \n";
                    $posttext .= "{$shortname} -> {$strforums} -> " . format_string($forum->name, true);
                    if ($discussion->name != $forum->name) {
                        $posttext .= " -> " . format_string($discussion->name, true);
                    }
                    $posttext .= "\n";
                    $posttext .= $CFG->wwwroot . '/mod/forum/discuss.php?d=' . $discussion->id;
                    $posttext .= "\n";
                    $posthtml .= "<p><font face=\"sans-serif\">" . "<a target=\"_blank\" href=\"{$CFG->wwwroot}/course/view.php?id={$course->id}\">{$shortname}</a> -> " . "<a target=\"_blank\" href=\"{$CFG->wwwroot}/mod/forum/index.php?id={$course->id}\">{$strforums}</a> -> " . "<a target=\"_blank\" href=\"{$CFG->wwwroot}/mod/forum/view.php?f={$forum->id}\">" . format_string($forum->name, true) . "</a>";
                    if ($discussion->name == $forum->name) {
                        $posthtml .= "</font></p>";
                    } else {
                        $posthtml .= " -> <a target=\"_blank\" href=\"{$CFG->wwwroot}/mod/forum/discuss.php?d={$discussion->id}\">" . format_string($discussion->name, true) . "</a></font></p>";
                    }
                    $posthtml .= '<p>';
                    $postsarray = $discussionposts[$discussionid];
                    sort($postsarray);
                    $sentcount = 0;
                    foreach ($postsarray as $postid) {
                        $post = $posts[$postid];
                        if (array_key_exists($post->userid, $users)) {
                            // we might know him/her already
                            $userfrom = $users[$post->userid];
                            if (!isset($userfrom->idnumber)) {
                                $userfrom = $DB->get_record('user', array('id' => $userfrom->id));
                                forum_cron_minimise_user_record($userfrom);
                            }
                        } else {
                            if ($userfrom = $DB->get_record('user', array('id' => $post->userid))) {
                                forum_cron_minimise_user_record($userfrom);
                                if ($userscount <= FORUM_CRON_USER_CACHE) {
                                    $userscount++;
                                    $users[$userfrom->id] = $userfrom;
                                }
                            } else {
                                mtrace('Could not find user ' . $post->userid);
                                continue;
                            }
                        }
                        if (!isset($userfrom->groups[$forum->id])) {
                            if (!isset($userfrom->groups)) {
                                $userfrom->groups = array();
                                if (isset($users[$userfrom->id])) {
                                    $users[$userfrom->id]->groups = array();
                                }
                            }
                            $userfrom->groups[$forum->id] = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
                            if (isset($users[$userfrom->id])) {
                                $users[$userfrom->id]->groups[$forum->id] = $userfrom->groups[$forum->id];
                            }
                        }
                        // Headers to help prevent auto-responders.
                        $userfrom->customheaders = array("Precedence: Bulk", 'X-Auto-Response-Suppress: All', 'Auto-Submitted: auto-generated');
                        $maildigest = forum_get_user_maildigest_bulk($digests, $userto, $forum->id);
                        if (!isset($userto->canpost[$discussion->id])) {
                            $canreply = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
                        } else {
                            $canreply = $userto->canpost[$discussion->id];
                        }
                        $data = new \mod_forum\output\forum_post_email($course, $cm, $forum, $discussion, $post, $userfrom, $userto, $canreply);
                        if (!isset($userto->viewfullnames[$forum->id])) {
                            $data->viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
                        } else {
                            $data->viewfullnames = $userto->viewfullnames[$forum->id];
                        }
                        if ($maildigest == 2) {
                            // Subjects and link only.
                            $posttext .= $textdigestbasicout->render($data);
                            $posthtml .= $htmldigestbasicout->render($data);
                        } else {
                            // The full treatment.
                            $posttext .= $textdigestfullout->render($data);
                            $posthtml .= $htmldigestfullout->render($data);
                            // Create an array of postid's for this user to mark as read.
                            if (!$CFG->forum_usermarksread) {
                                $userto->markposts[$post->id] = $post->id;
                            }
                        }
                        $sentcount++;
                    }
                    $footerlinks = array();
                    if ($canunsubscribe) {
                        $footerlinks[] = "<a href=\"{$CFG->wwwroot}/mod/forum/subscribe.php?id={$forum->id}\">" . get_string("unsubscribe", "forum") . "</a>";
                    } else {
                        $footerlinks[] = get_string("everyoneissubscribed", "forum");
                    }
                    $footerlinks[] = "<a href='{$CFG->wwwroot}/mod/forum/index.php?id={$forum->course}'>" . get_string("digestmailpost", "forum") . '</a>';
                    $posthtml .= "\n<div class='mdl-right'><font size=\"1\">" . implode('&nbsp;', $footerlinks) . '</font></div>';
                    $posthtml .= '<hr size="1" noshade="noshade" /></p>';
                }
                if (empty($userto->mailformat) || $userto->mailformat != 1) {
                    // This user DOESN'T want to receive HTML
                    $posthtml = '';
                }
                $eventdata = new \core\message\message();
                $eventdata->courseid = SITEID;
                $eventdata->component = 'mod_forum';
                $eventdata->name = 'digests';
                $eventdata->userfrom = core_user::get_noreply_user();
                $eventdata->userto = $userto;
                $eventdata->subject = $postsubject;
                $eventdata->fullmessage = $posttext;
                $eventdata->fullmessageformat = FORMAT_PLAIN;
                $eventdata->fullmessagehtml = $posthtml;
                $eventdata->notification = 1;
                $eventdata->smallmessage = get_string('smallmessagedigest', 'forum', $sentcount);
                $mailresult = message_send($eventdata);
                if (!$mailresult) {
                    mtrace("ERROR: mod/forum/cron.php: Could not send out digest mail to user {$userto->id} " . "({$userto->email})... not trying again.");
                } else {
                    mtrace("success.");
                    $usermailcount++;
                    // Mark post as read if forum_usermarksread is set off
                    if (get_user_preferences('forum_markasreadonnotification', 1, $userto->id) == 1) {
                        forum_tp_mark_posts_read($userto, $userto->markposts);
                    }
                }
            }
        }
        /// We have finishied all digest emails, update $CFG->digestmailtimelast
        set_config('digestmailtimelast', $timenow);
    }
    cron_setup_user();
    if (!empty($usermailcount)) {
        mtrace(get_string('digestsentusers', 'forum', $usermailcount));
    }
    if (!empty($CFG->forum_lastreadclean)) {
        $timenow = time();
        if ($CFG->forum_lastreadclean + 24 * 3600 < $timenow) {
            set_config('forum_lastreadclean', $timenow);
            mtrace('Removing old forum read tracking info...');
            forum_tp_clean_read_records();
        }
    } else {
        set_config('forum_lastreadclean', time());
    }
    return true;
}