Пример #1
0
/**
 * Run scheduled tasks according to a cron spec.
 */
function elis_cron()
{
    global $CFG;
    require $CFG->dirroot . '/elis/core/lib/tasklib.php';
    $timenow = time();
    // get all tasks that are (over-)due
    $tasks = get_recordset_select('elis_scheduled_tasks', 'nextruntime <= ' . $timenow, 'nextruntime ASC');
    if (empty($tasks)) {
        return;
    }
    while ($task = rs_fetch_next_record($tasks)) {
        $starttime = microtime();
        mtrace("Running {$task->callfunction}({$task->taskname}) from {$task->plugin}...");
        if ($task->enddate !== null && $task->enddate < $timenow) {
            mtrace('* Cancelling task: past end date');
            delete_records('elis_scheduled_tasks', 'id', $task->id);
            continue;
        }
        // FIXME: check for blocking tasks
        // FIXME: check if task is locked
        // See if some other cron has already run the function while we were
        // doing something else -- if so, skip it.
        $nextrun = get_field('elis_scheduled_tasks', 'nextruntime', 'id', $task->id);
        if ($nextrun > $timenow) {
            mtrace('* Skipped (someone else already ran it)');
            continue;
        }
        // calculate the next run time
        $newtask = new stdClass();
        $newtask->id = $task->id;
        $newtask->lastruntime = time();
        $newtask->nextruntime = cron_next_run_time($newtask->lastruntime, (array) $task);
        // see if we have any runs left
        if ($task->runsremaining !== null) {
            $newtask->runsremaining = $task->runsremaining - 1;
            if ($newtask->runsremaining <= 0) {
                mtrace('* Cancelling task: no runs left');
                delete_records('elis_scheduled_tasks', 'id', $task->id);
            } else {
                update_record('elis_scheduled_tasks', $newtask);
            }
        } else {
            update_record('elis_scheduled_tasks', $newtask);
        }
        // load the file and call the function
        if ($task->callfile) {
            $callfile = $CFG->dirroot . $task->callfile;
            if (!is_readable($callfile)) {
                mtrace('* Skipped (file not found)');
                continue;
            }
            require_once $callfile;
        }
        call_user_func(unserialize($task->callfunction), $task->taskname);
        $difftime = microtime_diff($starttime, microtime());
        mtrace("* {$difftime} seconds");
    }
}
function add_selection_all($ufiltering)
{
    global $SESSION;
    $guest = get_guest();
    $sqlwhere = $ufiltering->get_sql_filter("id<>{$guest->id} AND deleted <> 1");
    if ($rs = get_recordset_select('user', $sqlwhere, 'fullname', 'id,' . sql_fullname() . ' AS fullname')) {
        while ($user = rs_fetch_next_record($rs)) {
            if (!isset($SESSION->bulk_users[$user->id])) {
                $SESSION->bulk_users[$user->id] = $user->id;
            }
        }
        rs_close($rs);
    }
}
Пример #3
0
/**
 * Retrieves a list of note objects with specific atributes.
 *
 * @param int    $courseid id of the course in which the notes were posted (0 means any)
 * @param int    $userid id of the user to which the notes refer (0 means any)
 * @param string $state state of the notes (i.e. draft, public, site) ('' means any)
 * @param int    $author id of the user who modified the note last time (0 means any)
 * @param string $order an order to sort the results in
 * @param int    $limitfrom number of records to skip (offset)
 * @param int    $limitnum number of records to fetch
 * @return array of note objects
 */
function note_list($courseid = 0, $userid = 0, $state = '', $author = 0, $order = 'lastmodified DESC', $limitfrom = 0, $limitnum = 0)
{
    // setup filters
    $selects = array();
    if ($courseid) {
        $selects[] = 'courseid=' . $courseid;
    }
    if ($userid) {
        $selects[] = 'userid=' . $userid;
    }
    if ($author) {
        $selects[] = 'usermodified=' . $author;
    }
    if ($state) {
        $selects[] = "publishstate='{$state}'";
    }
    $selects[] = "module='notes'";
    $select = implode(' AND ', $selects);
    $fields = 'id,courseid,userid,content,format,created,lastmodified,usermodified,publishstate';
    // retrieve data
    $rs =& get_recordset_select('post', $select, $order, $fields, $limitfrom, $limitnum);
    return recordset_to_array($rs);
}
Пример #4
0
function bulkexport_submit(Pieform $form, $values)
{
    global $SESSION;
    $usernames = array();
    // Read in the usernames explicitly specified
    foreach (explode("\n", $values['usernames']) as $username) {
        $username = trim($username);
        if (!empty($username)) {
            $usernames[] = $username;
        }
    }
    if (empty($usernames) and !empty($values['authinstance'])) {
        // Export all users from the selected institution
        $rs = get_recordset_select('usr', 'authinstance = ? AND deleted = 0', array($values['authinstance']), '', 'username');
        while ($record = $rs->FetchRow()) {
            $usernames[] = $record['username'];
        }
    }
    $SESSION->set('exportdata', $usernames);
    $smarty = smarty();
    $smarty->assign('heading', '');
    $smarty->display('admin/users/bulkdownload.tpl');
    exit;
}
* @param string $folio_control_page_edit_security_custom The custom level of security for the page.
**/
// Note, this is ../ insead of ../../../ because we're called by files in /_folio, and not from the folder that this
//	page is actually residing inside of.
require_once '../includes.php';
$security_ident = -1;
// Load variables
$page_ident = required_param('page_ident', PARAM_INT);
$security_type = optional_param('folio_control_page_edit_security_type', '-1');
$security_parent = optional_param('folio_control_page_edit_security_parent', -1, PARAM_INT);
$security_custom = optional_param('folio_control_page_edit_security_custom', '-1');
// Test to see if we're logged in.
if (!isloggedin()) {
    // Since the user isn't logged in, don't allow them to change the security settings for the page.
    //	Get the previous copy's information.
    $pages = recordset_to_array(get_recordset_select('folio_page', "page_ident = {$page_ident} and newest= 1", null, 'title', '*'));
    if (!$pages[$page_ident]) {
        // Not found.
        error(' Unable to retrieve old record in folio_actions on line 46 for page ' . $page_ident . '.  You may have tried to create a new page without logging in.' . '  Please log in and try again.');
    } else {
        $security_ident = $pages[$page_ident]->security_ident;
    }
} else {
    // Since we're logged in, allow user to set permissions.
    // Check to see if we're inheriting.
    if ($security_type == 'Parent') {
        // Inheriting
        $security_ident = $security_parent;
    } else {
        // Set to a custom security level.  We'll need to insert/update the security record.
        $security_ident = $page_ident;
Пример #6
0
/**
 * Rebuilds the cached list of course activities stored in the database
 * @param int $courseid - id of course to rebuil, empty means all
 * @param boolean $clearonly - only clear the modinfo fields, gets rebuild automatically on the fly
 */
function rebuild_course_cache($courseid = 0, $clearonly = false)
{
    global $COURSE;
    if ($clearonly) {
        $courseselect = empty($courseid) ? "" : "id = {$courseid}";
        set_field_select('course', 'modinfo', null, $courseselect);
        // update cached global COURSE too ;-)
        if ($courseid == $COURSE->id) {
            $COURSE->modinfo = null;
        }
        // reset the fast modinfo cache
        $reset = 'reset';
        get_fast_modinfo($reset);
        return;
    }
    if ($courseid) {
        $select = "id = '{$courseid}'";
    } else {
        $select = "";
        @set_time_limit(0);
        // this could take a while!   MDL-10954
    }
    if ($rs = get_recordset_select("course", $select, '', 'id,fullname')) {
        while ($course = rs_fetch_next_record($rs)) {
            $modinfo = serialize(get_array_of_activities($course->id));
            if (!set_field("course", "modinfo", $modinfo, "id", $course->id)) {
                notify("Could not cache module information for course '" . format_string($course->fullname) . "'!");
            }
            // update cached global COURSE too ;-)
            if ($course->id == $COURSE->id) {
                $COURSE->modinfo = $modinfo;
            }
        }
        rs_close($rs);
    }
    // reset the fast modinfo cache
    $reset = 'reset';
    get_fast_modinfo($reset);
}
Пример #7
0
/**
 * Process a chunk of the task
 *
 * @param array $state the task state
 */
function user_activity_task_process(&$state)
{
    global $CFG;
    $sessiontimeout = $state['sessiontimeout'];
    $sessiontail = $state['sessiontail'];
    $starttime = $state['starttime'];
    // find the record ID corresponding to our start time
    $startrec = get_field_select('log', 'MIN(id)', "time >= {$starttime}");
    $startrec = empty($startrec) ? 0 : $startrec;
    // find the last record that's close to our chunk size, without
    // splitting a second between runs
    $endtime = get_field_select('log', 'MIN(time)', 'id >= ' . ($startrec + USERACT_RECORD_CHUNK));
    if (!$endtime) {
        $endtime = time();
    }
    // Get the logs between the last time we ran, and the current time.  Sort
    // by userid (so all records for a given user are together), and then by
    // time (so that we process a user's logs sequentially).
    $recstarttime = max(0, $starttime - $state['sessiontimeout']);
    $rs = get_recordset_select('log', "time >= {$recstarttime} AND time < {$endtime} AND userid != 0", 'userid, time');
    if ($CFG->debug >= DEBUG_ALL) {
        mtrace("* processing records from time:{$starttime} to time:{$endtime}");
    }
    $curuser = -1;
    $session_start = 0;
    $last_course = -1;
    $module_session_start = 0;
    $last_module = -1;
    $last_time = 0;
    if ($rs) {
        while ($rec = rs_fetch_next_record($rs)) {
            if ($rec->userid != $curuser) {
                // end of user's record
                if ($curuser > 0 && $session_start > 0) {
                    // flush current session data
                    if ($last_time > $endtime - $sessiontimeout) {
                        /* Last record is within the session timeout of our end
                         * time for this run.  Just use our last logged time as
                         * the session end time, and the rest will be picked up
                         * by the next run of the sessionizer. */
                        $session_end = $last_time;
                    } else {
                        /* Last record is not within the session timeout of our
                         * end time for this run, so do our normal session
                         * ending. */
                        $session_end = $last_time + $sessiontail;
                    }
                    user_activity_add_session($curuser, $last_course, $session_start, $session_end);
                    if ($last_module > 0) {
                        user_module_activity_add_session($curuser, $last_course, $last_module, $module_session_start, $session_end);
                    }
                }
                $curuser = $rec->userid;
                $session_start = 0;
                $last_course = -1;
                $module_session_start = 0;
                $last_module = -1;
                $last_time = 0;
            }
            if ($rec->time < $starttime) {
                // Find the last log for the user before our start time, that's
                // within the session timeout, and start the session with that
                // record.
                $session_start = $rec->time;
                $last_time = $rec->time;
                $last_course = $rec->course;
                $module_session_start = $rec->time;
                $last_module = $rec->cmid;
            } elseif ($rec->time > $last_time + $sessiontimeout) {
                if ($last_course >= 0) {
                    // session timed out -- add record
                    if (defined('ETLUA_EXTRA_DEBUG') && $CFG->debug >= DEBUG_DEVELOPER) {
                        mtrace('** session timed out');
                    }
                    $session_end = $last_time + $sessiontail;
                    user_activity_add_session($curuser, $last_course, $session_start, $session_end);
                    if ($last_module > 0) {
                        user_module_activity_add_session($curuser, $last_course, $last_module, $module_session_start, $session_end);
                    }
                }
                // start a new session with the current record
                $session_start = $rec->time;
                $last_course = $rec->course;
                $module_session_start = $rec->time;
                $last_module = $rec->cmid;
            } elseif ($rec->action === 'logout') {
                // user logged out -- add record
                if (defined('ETLUA_EXTRA_DEBUG') && $CFG->debug >= DEBUG_DEVELOPER) {
                    mtrace('** user logged out');
                }
                $session_end = $rec->time;
                user_activity_add_session($curuser, $last_course, $session_start, $session_end);
                if ($last_module > 0) {
                    user_module_activity_add_session($curuser, $last_course, $last_module, $module_session_start, $session_end);
                }
                // clear session info
                $session_start = 0;
                $module_session_start = 0;
            } elseif ($rec->course != $last_course) {
                // user switched to a different course -- start new session record
                if ($last_course >= 0) {
                    if (defined('ETLUA_EXTRA_DEBUG') && $CFG->debug >= DEBUG_DEVELOPER) {
                        mtrace('** user switched courses');
                    }
                    $session_end = $rec->time;
                    user_activity_add_session($curuser, $last_course, $session_start, $session_end);
                    if ($last_module > 0) {
                        user_module_activity_add_session($curuser, $last_course, $last_module, $module_session_start, $session_end);
                    }
                }
                $session_start = $rec->time;
                $last_course = $rec->course;
                $module_session_start = $rec->time;
                $last_module = $rec->cmid;
            } elseif ($rec->cmid != $last_module) {
                // user switched to a different module -- start new module session
                if ($last_module > 0) {
                    if (defined('ETLUA_EXTRA_DEBUG') && $CFG->debug >= DEBUG_DEVELOPER) {
                        mtrace('** user switched modules');
                    }
                    $session_end = $rec->time;
                    user_module_activity_add_session($curuser, $last_course, $last_module, $module_session_start, $session_end);
                }
                $module_session_start = $rec->time;
                $last_module = $rec->cmid;
            }
            $last_time = $rec->time;
        }
    }
    if ($curuser > 0 && $session_start > 0) {
        // flush session data
        if ($last_time > $endtime - $sessiontimeout) {
            $session_end = $last_time;
        } else {
            $session_end = $last_time + $sessiontail;
        }
        user_activity_add_session($curuser, $last_course, $session_start, $session_end);
    }
    $state['starttime'] = $endtime;
    $endrec = get_field_select('log', 'MAX(id)', "time < {$endtime}");
    // possibly skip the last time when calculating the total number of
    // records, since we are purposely skipping anything less than $endtime
    $lasttime = get_field_select('log', 'MAX(time)', 'TRUE');
    $totalrec = get_field_select('log', 'MAX(id)', "time < {$lasttime}");
    $totalrec = max($totalrec, $endrec);
    return array($endrec ? $endrec - $state['startrec'] : 0, $totalrec ? $totalrec - $state['startrec'] : 0);
}
Пример #8
0
 /**
  * Factory method - uses the parameters to retrieve all matching instances from the DB.
  * @static final protected
  * @return mixed array of object instances or false if not found
  */
 function fetch_all_helper($table, $classname, $params)
 {
     $instance = new $classname();
     $classvars = (array) $instance;
     $params = (array) $params;
     $wheresql = array();
     // remove incorrect params
     foreach ($params as $var => $value) {
         if (!in_array($var, $instance->required_fields) and !array_key_exists($var, $instance->optional_fields)) {
             continue;
         }
         if (is_null($value)) {
             $wheresql[] = " {$var} IS NULL ";
         } else {
             $value = addslashes($value);
             $wheresql[] = " {$var} = '{$value}' ";
         }
     }
     if (empty($wheresql)) {
         $wheresql = '';
     } else {
         $wheresql = implode("AND", $wheresql);
     }
     if ($rs = get_recordset_select($table, $wheresql, 'id')) {
         $result = array();
         while ($data = rs_fetch_next_record($rs)) {
             $instance = new $classname();
             grade_object::set_properties($instance, $data);
             $result[$instance->id] = $instance;
         }
         rs_close($rs);
         return $result;
     } else {
         return false;
     }
 }
Пример #9
0
 function get_submission($userid = 0, $createnew = false, $teachermodified = false)
 {
     global $CFG;
     $submission = parent::get_submission($userid, $createnew, $teachermodified);
     if ($submission) {
         $onlinejudge = get_record('assignment_oj_submissions', 'submission', $submission->id);
         if (empty($onlinejudge) && $createnew) {
             $newsubmission = new Object();
             $newsubmission->submission = $submission->id;
             if (!insert_record("assignment_oj_submissions", $newsubmission)) {
                 error("Could not insert a new empty onlinejudge submission");
             }
             unset($newsubmission);
         }
         $onlinejudge = get_record('assignment_oj_submissions', 'submission', $submission->id);
         if ($onlinejudge) {
             $submission->judged = $onlinejudge->judged;
             $submission->oj_id = $onlinejudge->id;
         } else {
             $submission->judged = 0;
         }
         if ($submission->judged) {
             $results = get_recordset_select('assignment_oj_results', 'submission = ' . $submission->id . ' AND judgetime >= ' . $submission->timemodified, 'judgetime DESC', '*', '', '1');
             $results = recordset_to_array($results);
             if ($results) {
                 $result = array_pop($results);
                 $submission->info = $result->info;
                 $submission->status = $result->status;
                 $submission->judgetime = $result->judgetime;
                 $submission->output = $result->output;
             } else {
                 $submission->judged = 0;
                 //It is been judging
                 $submission->status = 'pending';
             }
         } else {
             if (($files = get_directory_list($CFG->dataroot . '/' . $this->file_area_name($userid))) && count($files) != 0) {
                 // Submitted but unjudged
                 $submission->status = 'pending';
             }
         }
     }
     return $submission;
 }
Пример #10
0
 /**
  * Performs the necessary calculations on the grades_final referenced by this grade_item.
  * Also resets the needsupdate flag once successfully performed.
  *
  * This function must be used ONLY from lib/gradeslib.php/grade_regrade_final_grades(),
  * because the regrading must be done in correct order!!
  *
  * @return boolean true if ok, error string otherwise
  */
 function regrade_final_grades($userid = null)
 {
     global $CFG;
     // locked grade items already have correct final grades
     if ($this->is_locked()) {
         return true;
     }
     // calculation produces final value using formula from other final values
     if ($this->is_calculated()) {
         if ($this->compute($userid)) {
             return true;
         } else {
             return "Could not calculate grades for grade item";
             // TODO: improve and localize
         }
         // noncalculated outcomes already have final values - raw grades not used
     } else {
         if ($this->is_outcome_item()) {
             return true;
             // aggregate the category grade
         } else {
             if ($this->is_category_item() or $this->is_course_item()) {
                 // aggregate category grade item
                 $category = $this->get_item_category();
                 $category->grade_item =& $this;
                 if ($category->generate_grades($userid)) {
                     return true;
                 } else {
                     return "Could not aggregate final grades for category:" . $this->id;
                     // TODO: improve and localize
                 }
             } else {
                 if ($this->is_manual_item()) {
                     // manual items track only final grades, no raw grades
                     return true;
                 } else {
                     if (!$this->is_raw_used()) {
                         // hmm - raw grades are not used- nothing to regrade
                         return true;
                     }
                 }
             }
         }
     }
     // normal grade item - just new final grades
     $result = true;
     $grade_inst = new grade_grade();
     $fields = implode(',', $grade_inst->required_fields);
     if ($userid) {
         $rs = get_recordset_select('grade_grades', "itemid={$this->id} AND userid={$userid}", '', $fields);
     } else {
         $rs = get_recordset('grade_grades', 'itemid', $this->id, '', $fields);
     }
     if ($rs) {
         while ($grade_record = rs_fetch_next_record($rs)) {
             $grade = new grade_grade($grade_record, false);
             if (!empty($grade_record->locked) or !empty($grade_record->overridden)) {
                 // this grade is locked - final grade must be ok
                 continue;
             }
             $grade->finalgrade = $this->adjust_raw_grade($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
             if (grade_floats_different($grade_record->finalgrade, $grade->finalgrade)) {
                 if (!$grade->update('system')) {
                     $result = "Internal error updating final grade";
                 }
             }
         }
         rs_close($rs);
     }
     return $result;
 }
Пример #11
0
/**
* Gets the default category in the most specific context.
* If no categories exist yet then default ones are created in all contexts.
*
* @param array $contexts  The context objects for this context and all parent contexts.
* @return object The default category - the category in the course context
*/
function question_make_default_categories($contexts)
{
    $toreturn = null;
    // If it already exists, just return it.
    foreach ($contexts as $key => $context) {
        if (!($categoryrs = get_recordset_select("question_categories", "contextid = '{$context->id}'", 'sortorder, name', '*', '', 1))) {
            error('error getting category record');
        } else {
            if (!($category = rs_fetch_record($categoryrs))) {
                // Otherwise, we need to make one
                $category = new stdClass();
                $contextname = print_context_name($context, false, true);
                $category->name = addslashes(get_string('defaultfor', 'question', $contextname));
                $category->info = addslashes(get_string('defaultinfofor', 'question', $contextname));
                $category->contextid = $context->id;
                $category->parent = 0;
                $category->sortorder = 999;
                // By default, all categories get this number, and are sorted alphabetically.
                $category->stamp = make_unique_id_code();
                if (!($category->id = insert_record('question_categories', $category))) {
                    error('Error creating a default category for context ' . print_context_name($context));
                }
            }
        }
        if ($context->contextlevel == CONTEXT_COURSE) {
            $toreturn = clone $category;
        }
    }
    return $toreturn;
}
Пример #12
0
$lasttime = optional_param('lasttime', 0, PARAM_INT);
$CFG->limitviewentries = !isset($CFG->limitviewentries) || empty($CFG->limitviewentries) ? 600 : 6 * $CFG->limitviewentries;
//add_to_log(1, 1, "filter: $filter, lasttime: $lasttime", true);  //debug mode
// check for the lastes entries in the log
$where = "id > '{$lasttime}'";
if ($filter != '') {
    $where .= " AND ip = '{$filter}'";
}
if (!($count = count_records_select('log', $where))) {
    $return = '{"response":""}';
    //add_to_log(1, 1, $return, true); //debug mode
    echo $return;
    die;
}
$count = $count > $CFG->limitviewentries ? $count - $CFG->limitviewentries : 0;
if (!($entries = get_recordset_select('log', $where, 'time ASC', '*', $count, $CFG->limitviewentries))) {
    $return = '{"response":"KO"}';
    //add_to_log(1, 1, $return, true); //debug mode
    echo $return;
    die;
}
if (!($entries = recordset_to_array($entries))) {
    $return = '{"response":""}';
    //add_to_log(1, 1, $return, true); //debug mode
    echo $return;
    die;
}
/// set return entries in json format {"response":[{"ip":"","time":"","smarttime":"","category":"","info":""}]}
$return = '{"response":[';
foreach ($entries as $entri) {
    /// search for category names
Пример #13
0
/**
* Gets the list of categories for the user or for the group
* @param $groupid Id of the group for which we need the categories'list. If 0 or NULL, then get the list of categories of the user
*/
function fm_get_cat_list($groupid = 0)
{
    global $USER;
    // $cats = array();
    $cats[0] = get_string('btnnoassigncat', 'block_file_manager');
    if ($groupid == 0) {
        $ownertype = OWNERISUSER;
        $rs = get_recordset_select('fmanager_categories', "owner={$USER->id} AND ownertype={$ownertype}", 'name');
        $catsrec = recordset_to_array($rs);
    } else {
        $ownertype = OWNERISGROUP;
        $rs = get_recordset_select('fmanager_categories', "owner={$groupid} AND ownertype={$ownertype}", 'name');
        $catsrec = recordset_to_array($rs);
    }
    if ($catsrec) {
        foreach ($catsrec as $c) {
            $cats[$c->id] = $c->name;
        }
    }
    return $cats;
}
Пример #14
0
* script for bulk user delete operations
*/
require_once '../../config.php';
require_once $CFG->libdir . '/adminlib.php';
$confirm = optional_param('confirm', 0, PARAM_BOOL);
admin_externalpage_setup('userbulk');
require_capability('moodle/user:update', get_context_instance(CONTEXT_SYSTEM));
$return = $CFG->wwwroot . '/' . $CFG->admin . '/user/user_bulk.php';
if (empty($SESSION->bulk_users)) {
    redirect($return);
}
admin_externalpage_print_header();
//TODO: add support for large number of users
if ($confirm and confirm_sesskey()) {
    $in = implode(',', $SESSION->bulk_users);
    if ($rs = get_recordset_select('user', "id IN ({$in})", '', 'id, username, secret, confirmed, auth, firstname, lastname')) {
        while ($user = rs_fetch_next_record($rs)) {
            if ($user->confirmed) {
                continue;
            }
            $auth = get_auth_plugin($user->auth);
            $result = $auth->user_confirm(addslashes($user->username), addslashes($user->secret));
            if ($result != AUTH_CONFIRM_OK && $result != AUTH_CONFIRM_ALREADY) {
                notify(get_string('usernotconfirmed', '', fullname($user, true)));
            }
        }
        rs_close($rs);
    }
    redirect($return, get_string('changessaved'));
} else {
    $in = implode(',', $SESSION->bulk_users);
Пример #15
0
 /**
  * Update grades for this class
  *
  * @param array The class grades
  */
 function update_all_class_grades($classgrades = array())
 {
     global $CURMAN;
     if (isset($this->course) && get_class($this->course) == 'course') {
         $elements = $this->course->get_completion_elements();
     } else {
         $elements = false;
     }
     $timenow = time();
     if (!empty($elements)) {
         // for each student, find out how many required completion elements are
         // incomplete, and when the last completion element was graded
         $sql = "SELECT s.*, grades.incomplete, grades.maxtime\n                      FROM {$CURMAN->db->prefix_table(STUTABLE)} s\n                      JOIN (SELECT s.userid, COUNT(CASE WHEN grades.id IS NULL AND cc.required = 1 THEN 1\n                                                        ELSE NULL END) AS incomplete,\n                                    MAX(timegraded) AS maxtime\n                              FROM {$CURMAN->db->prefix_table(STUTABLE)} s\n                              JOIN {$CURMAN->db->prefix_table(CRSCOMPTABLE)} cc\n                                   ON cc.courseid = {$this->courseid}\n                         LEFT JOIN {$CURMAN->db->prefix_table(CLSGRTABLE)} grades\n                                   ON grades.userid = s.userid\n                                      AND grades.completionid = cc.id\n                                      AND grades.classid = {$this->id}\n                                      AND grades.grade >= cc.completion_grade\n                             WHERE s.classid = {$this->id} AND s.locked = 0\n                          GROUP BY s.userid\n                           ) grades ON grades.userid = s.userid\n                     WHERE s.classid = {$this->id} AND s.locked = 0";
         $rs = get_recordset_sql($sql);
         if ($rs) {
             while ($rec = rs_fetch_next_record($rs)) {
                 if ($rec->incomplete == 0 && $rec->grade > 0 && $rec->grade >= $this->course->completion_grade) {
                     $student = new student($rec, $this, null);
                     $student->completestatusid = STUSTATUS_PASSED;
                     $student->completetime = $rec->maxtime;
                     $student->credits = $this->course->credits;
                     $student->locked = 1;
                     $student->complete();
                 }
             }
         }
     } else {
         /// We have no completion elements so just make sure the user's grade is at least the
         /// minimum value required for the course.
         /// Get all unlocked enrolments
         $select = "classid = {$this->id} AND locked = 0";
         $rs = get_recordset_select(STUTABLE, $select, 'userid');
         if ($rs) {
             while ($rec = rs_fetch_next_record($rs)) {
                 if ($rec->grade > 0 && $rec->grade >= $this->course->completion_grade) {
                     $student = new student($rec, $this, null);
                     $student->completestatusid = STUSTATUS_PASSED;
                     $student->completetime = $timenow;
                     $student->credits = $this->course->credits;
                     $student->locked = 1;
                     $student->complete();
                 }
             }
         }
     }
 }
Пример #16
0
/**
 * Adds groups and group assignments at the site-level either globally
 * or for a particular cluster
 *
 * @param  int  $clusterid  The particular cluster's id, or zero for all
 */
function cluster_groups_update_site_course($clusterid = 0, $add_members = false, $userid = 0)
{
    global $CFG, $CURMAN;
    //make sure this functionality is even enabled
    if (!empty($CURMAN->config->site_course_cluster_groups)) {
        $select_parts = array();
        $cluster_select = '';
        if (!empty($clusterid)) {
            $select_parts[] = "(clst.id = {$clusterid})";
        }
        if (!empty($userid)) {
            $select_parts[] = "(mdluser.id = {$userid})";
        }
        $select = empty($select_parts) ? '' : 'WHERE ' . implode('AND', $select_parts);
        $siteid = SITEID;
        //query to get clusters, groups, and possibly users
        $sql = "SELECT grp.id AS groupid, clst.id AS clusterid, clst.name AS clustername, mdluser.id AS userid FROM\n                {$CURMAN->db->prefix_table(CLSTTABLE)} clst\n                LEFT JOIN {$CURMAN->db->prefix_table('groups')} grp\n                ON clst.name = grp.name\n                AND grp.courseid = {$siteid}\n                LEFT JOIN\n                    ({$CURMAN->db->prefix_table(CLSTUSERTABLE)} usrclst\n                     JOIN {$CURMAN->db->prefix_table(USRTABLE)} crlmuser\n                     ON usrclst.userid = crlmuser.id\n                     JOIN {$CURMAN->db->prefix_table('user')} mdluser\n                     ON crlmuser.idnumber = mdluser.idnumber)\n                ON clst.id = usrclst.clusterid\n                {$select}\n                ORDER BY clst.id";
        if ($recordset = get_recordset_sql($sql)) {
            $last_clusterid = 0;
            $last_group_id = 0;
            while ($record = rs_fetch_next_record($recordset)) {
                if ($last_clusterid != $record->clusterid) {
                    $last_group_id = $record->groupid;
                }
                if (cluster_groups_cluster_allows_groups($record->clusterid)) {
                    //handle group record
                    if (empty($record->groupid) && (empty($last_clusterid) || $last_clusterid !== $record->clusterid)) {
                        //create group
                        $group = new stdClass();
                        $group->courseid = SITEID;
                        $group->name = addslashes($record->clustername);
                        $group->id = groups_create_group($group);
                        $last_group_id = $group->id;
                    }
                    //handle adding members
                    if ($add_members && !empty($last_group_id) && !empty($record->userid)) {
                        cluster_groups_add_member($last_group_id, $record->userid);
                    }
                    //set up groupings
                    if (empty($last_clusterid) || $last_clusterid !== $record->clusterid) {
                        cluster_groups_grouping_helper($record->clusterid, $record->clustername);
                    }
                }
                $last_clusterid = $record->clusterid;
            }
        }
    }
    if (!empty($CFG->enablegroupings) && !empty($CURMAN->config->cluster_groupings)) {
        //query condition
        $select = '1 = 1';
        if (!empty($clusterid)) {
            $select = "id = {$clusterid}";
        }
        //go through all appropriate clusters
        if ($recordset = get_recordset_select(CLSTTABLE, $select)) {
            while ($record = rs_fetch_next_record($recordset)) {
                //set up groupings
                cluster_groups_grouping_helper($record->id, $record->name);
            }
        }
    }
    return true;
}
Пример #17
0
function bulkexport_submit(Pieform $form, $values)
{
    global $SESSION;
    $usernames = array();
    // Read in the usernames explicitly specified
    foreach (explode("\n", $values['usernames']) as $username) {
        $username = trim($username);
        if (!empty($username)) {
            $usernames[] = $username;
        }
    }
    if (empty($usernames) and !empty($values['authinstance'])) {
        // Export all users from the selected institution
        $rs = get_recordset_select('usr', 'authinstance = ? AND deleted = 0', array($values['authinstance']), '', 'username');
        while ($record = $rs->FetchRow()) {
            $usernames[] = $record['username'];
        }
    }
    safe_require('export', 'leap');
    $listing = array();
    $files = array();
    $exportcount = 0;
    $exporterrors = array();
    $num_users = count($usernames);
    foreach ($usernames as $username) {
        if (!($exportcount % 25)) {
            set_progress_info('bulkexport', $exportcount, $num_users, get_string('validating', 'admin'));
        }
        $user = new User();
        try {
            $user->find_by_username($username);
        } catch (AuthUnknownUserException $e) {
            continue;
            // Skip non-existent users
        }
        $exporter = new PluginExportLeap($user, PluginExport::EXPORT_ALL_VIEWS_COLLECTIONS, PluginExport::EXPORT_ALL_ARTEFACTS);
        try {
            $zipfile = $exporter->export();
        } catch (Exception $e) {
            $exporterrors[] = $username;
            continue;
        }
        $listing[] = array($username, $zipfile);
        $files[] = $exporter->get('exportdir') . $zipfile;
        $exportcount++;
    }
    if (!($zipfile = create_zipfile($listing, $files))) {
        export_iframe_die(get_string('bulkexportempty', 'admin'));
    }
    log_info("Exported {$exportcount} users to {$zipfile}");
    if (!empty($exporterrors)) {
        $SESSION->add_error_msg(get_string('couldnotexportusers', 'admin', implode(', ', $exporterrors)));
    }
    // Store the filename in the session, and redirect the iframe to it to trigger
    // the download. Here it would be nice to trigger the download for everyone,
    // but alas this is not possible for people without javascript.
    $SESSION->set('exportfile', $zipfile);
    set_progress_done('bulkexport', array('redirect' => get_config('wwwroot') . 'admin/users/bulkexport.php'));
    // Download the export file once it has been generated
    require_once 'file.php';
    serve_file($zipfile, basename($zipfile), 'application/x-zip', array('lifetime' => 0, 'forcedownload' => true));
    // TODO: delete the zipfile (and temporary files) once it's been downloaded
}
Пример #18
0
/**
 * Unsets marked preferences
 *
 * @param  $to_delete  array    Array of preference key prefixes
 * @param  $temporary  boolean  If true, unset from temporary preferences, otherwise unset from
 *                              persistent preferences
 */
function php_report_filtering_unset_invalid_user_preferences($to_delete, $temporary)
{
    global $SESSION;
    if ($temporary) {
        //delete temporary preferences that are not valid
        if (!empty($to_delete) && !empty($SESSION->php_report_default_params)) {
            foreach ($to_delete as $item) {
                foreach ($SESSION->php_report_default_params as $key => $value) {
                    //prefix matches, so clear
                    if ($key == $item || strpos($key, $item . '_') === 0) {
                        unset($SESSION->php_report_default_params[$key]);
                    }
                }
            }
        }
    } else {
        //delete persistent preferences that are not valid
        if (!empty($to_delete)) {
            $conditions = array();
            //set up conditions for any valid prefix-matching
            foreach ($to_delete as $item) {
                $conditions[] = "name = '{$item}'";
                $conditions[] = 'name ' . sql_ilike() . " '{$item}_%'";
            }
            //try to be efficient in cases with a lot of data
            $where = implode(' OR ', $conditions);
            if ($recordset = get_recordset_select('user_preferences', $where)) {
                while ($record = rs_fetch_next_record($recordset)) {
                    //user proper API function to handle stored session info
                    unset_user_preference($record->name);
                }
            }
        }
    }
}
*/
require_once '../../config.php';
require_once $CFG->libdir . '/adminlib.php';
$confirm = optional_param('confirm', 0, PARAM_BOOL);
admin_externalpage_setup('userbulk');
require_capability('moodle/user:delete', get_context_instance(CONTEXT_SYSTEM));
$return = $CFG->wwwroot . '/' . $CFG->admin . '/user/user_bulk.php';
if (empty($SESSION->bulk_users)) {
    redirect($return);
}
admin_externalpage_print_header();
//TODO: add support for large number of users
if ($confirm and confirm_sesskey()) {
    $primaryadmin = get_admin();
    $in = implode(',', $SESSION->bulk_users);
    if ($rs = get_recordset_select('user', "id IN ({$in})")) {
        while ($user = rs_fetch_next_record($rs)) {
            if ($primaryadmin->id != $user->id and $USER->id != $user->id and delete_user($user)) {
                unset($SESSION->bulk_users[$user->id]);
            } else {
                notify(get_string('deletednot', '', fullname($user, true)));
            }
        }
        rs_close($rs);
    }
    redirect($return, get_string('changessaved'));
} else {
    $in = implode(',', $SESSION->bulk_users);
    $userlist = get_records_select_menu('user', "id IN ({$in})", 'fullname', 'id,' . sql_fullname() . ' AS fullname');
    $usernames = implode(', ', $userlist);
    $optionsyes = array();
Пример #20
0
/**
 * Calculates a new label for a copy of an existing PHP report schedule
 * based on the existing schedule's name
 *
 * @param   string  $parent_label  The label from the original schedule instance
 *
 * @return  string                 The label for the new schedule instance
 */
function block_php_report_get_copy_label($parent_label)
{
    //first guess at to our copy number
    $i = 1;
    $done = false;
    while (!$done) {
        //get the proposed label
        $a = new stdClass();
        $a->label = $parent_label;
        $a->index = $i;
        $label = get_string('task_copy_label', 'block_php_report', $a);
        //look for records containing the proposed namy anywhere in their config data
        //(may include false-positives but very unlikely)
        if ($records = get_recordset_select('php_report_schedule', 'config ' . sql_ilike() . " '%{$label}%'")) {
            //track whether an exact match was found
            $found = false;
            //go through all possible matches
            while ($record = rs_fetch_next_record($records)) {
                //perform an exact comparison
                $config = unserialize($record->config);
                if ($config['label'] == $label) {
                    //exact match
                    $found = true;
                    break;
                }
            }
            if (!$found) {
                //all cases were false, positive, so accept
                $done = true;
            } else {
                //exact match, so increment and try again
                $i++;
            }
        } else {
            //no config contained the proposed label, so accept
            $done = true;
        }
    }
    return $label;
}
Пример #21
0
/**
 * Get the first two columns from a number of records as an associative array.
 *
 * Arguments as for @see function get_recordset_select.
 * Return value as for @see function get_records_menu.
 *
 * @param string $table The database table to be checked against.
 * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
 * @param string $sort Sort order (optional) - a valid SQL order parameter
 * @param string $fields A comma separated list of fields to be returned from the chosen table.
 * @return mixed an associative array, or false if no records were found or an error occured.
 */
function get_records_select_menu($table, $select = '', $values = null, $sort = '', $fields = '*')
{
    $rs = get_recordset_select($table, $select, $values, $sort, $fields);
    return recordset_to_menu($rs);
}
Пример #22
0
/**
* Gets the default category in the most specific context.
* If no categories exist yet then default ones are created in all contexts.
*
* @param array $contexts  The context objects for this context and all parent contexts.
* @return object The default category - the category in the course context
*/
function question_make_default_categories($contexts)
{
    static $preferredlevels = array(CONTEXT_COURSE => 4, CONTEXT_MODULE => 3, CONTEXT_COURSECAT => 2, CONTEXT_SYSTEM => 1);
    $toreturn = null;
    $preferredness = 0;
    // If it already exists, just return it.
    foreach ($contexts as $key => $context) {
        if (!($categoryrs = get_recordset_select("question_categories", "contextid = '{$context->id}'", 'sortorder, name', '*', '', 1))) {
            error('error getting category record');
        } else {
            if (!($category = rs_fetch_record($categoryrs))) {
                // Otherwise, we need to make one
                $category = new stdClass();
                $contextname = print_context_name($context, false, true);
                $category->name = addslashes(get_string('defaultfor', 'question', $contextname));
                $category->info = addslashes(get_string('defaultinfofor', 'question', $contextname));
                $category->contextid = $context->id;
                $category->parent = 0;
                $category->sortorder = 999;
                // By default, all categories get this number, and are sorted alphabetically.
                $category->stamp = make_unique_id_code();
                if (!($category->id = insert_record('question_categories', $category))) {
                    error('Error creating a default category for context ' . print_context_name($context));
                }
            }
        }
        if ($preferredlevels[$context->contextlevel] > $preferredness && has_any_capability(array('moodle/question:usemine', 'moodle/question:useall'), $context)) {
            $toreturn = $category;
            $preferredness = $preferredlevels[$context->contextlevel];
        }
    }
    if (!is_null($toreturn)) {
        $toreturn = clone $toreturn;
    }
    return $toreturn;
}
Пример #23
0
/**
 * Get the first two columns from a number of records as an associative array.
 *
 * Arguments as for @see function get_recordset_select.
 * Return value as for @see function get_records_menu.
 *
 * @param string $table The database table to be checked against.
 * @param string $select A fragment of SQL to be used in a where clause in the SQL call.
 * @param string $sort Sort order (optional) - a valid SQL order parameter
 * @param string $fields A comma separated list of fields to be returned from the chosen table.
 * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
 * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
 * @return mixed an associative array, or false if no records were found or an error occured.
 */
function get_records_select_menu($table, $select = '', $sort = '', $fields = '*', $limitfrom = '', $limitnum = '')
{
    $rs = get_recordset_select($table, $select, $sort, $fields, $limitfrom, $limitnum);
    return recordset_to_menu($rs);
}
Пример #24
0
 public function update()
 {
     $result = parent::update();
     $result = $result && field_data::set_for_context_from_datarecord('curriculum', $this);
     // If this setting is changed, we need to update the existing curriclum expiration values (ELIS-1172)
     if ($rs = get_recordset_select(CURASSTABLE, "timeexpired != 0 AND curriculumid = {$this->id}", '', 'id, userid')) {
         $timenow = time();
         while ($curass = rs_fetch_next_record($rs)) {
             $update = new stdClass();
             $update->id = $curass->id;
             $update->timeexpired = calculate_curriculum_expiry(NULL, $this->id, $curass->userid);
             $update->timemodified = $timenow;
             update_record(CURASSTABLE, $update);
         }
         rs_close($rs);
     }
     return $result;
 }
Пример #25
0
function backup_copy_user_files($preferences)
{
    global $CFG;
    $status = true;
    //First we check that "user_files" exists and create it if necessary
    //in temp/backup/$backup_code  dir
    $status = check_and_create_user_files_dir($preferences->backup_unique_code);
    //now get a list of users that we need for this backup.
    $backup_users = get_recordset_select("backup_ids", "backup_code='{$preferences->backup_unique_code}' AND table_name='user'", "", "id, old_id");
    while ($user = rs_fetch_next_record($backup_users)) {
        //If this user's directory exists, copy it
        $userdir = make_user_directory($user->old_id, true);
        if (check_dir_exists($userdir)) {
            //first remove dirroot so we can split out the folders.
            $parts = explode('/', str_replace($CFG->dataroot . '/user/', '', $userdir));
            $status = true;
            if (is_array($parts)) {
                $group = $parts[0];
                $userid = $parts[1];
                // Create group dir first
                $status = check_dir_exists("{$CFG->dataroot}/temp/backup/{$preferences->backup_unique_code}/user_files/" . $group, true);
            }
            $status = $status && backup_copy_file($userdir, "{$CFG->dataroot}/temp/backup/{$preferences->backup_unique_code}/user_files/{$group}/{$user->old_id}");
        }
        //Do some output
        backup_flush(30);
    }
    rs_close($backup_users);
    return $status;
}
Пример #26
0
 /**
  * Lock the grade if needed - make sure this is called only when final grades are valid
  * @param array $items array of all grade item ids
  * @return void
  */
 function check_locktime_all($items)
 {
     global $CFG;
     $items_sql = implode(',', $items);
     $now = time();
     // no rounding needed, this is not supposed to be called every 10 seconds
     if ($rs = get_recordset_select('grade_grades', "itemid IN ({$items_sql}) AND locked = 0 AND locktime > 0 AND locktime < {$now}")) {
         while ($grade = rs_fetch_next_record($rs)) {
             $grade_grade = new grade_grade($grade, false);
             $grade_grade->locked = time();
             $grade_grade->update('locktime');
         }
         rs_close($rs);
     }
 }
Пример #27
0
 /**
  * This function is run by admin/cron.php every time if admin has enabled this plugin.
  *
  * Everyday at settlement time (default is 00:05), it cleans up some tables
  * and sends email to admin/teachers about pending orders expiring if manual-capture has enabled.
  *
  * If admin set up 'Order review' and 'Capture day', it captures credits cards and enrols students.
  *
  * @access public
  */
 function cron()
 {
     global $CFG;
     require_once $CFG->dirroot . '/enrol/authorize/authorizenetlib.php';
     $oneday = 86400;
     $timenow = time();
     $settlementtime = authorize_getsettletime($timenow);
     $timediff30 = $settlementtime - 30 * $oneday;
     $mconfig = get_config('enrol/authorize');
     mtrace("Processing authorize cron...");
     if (intval($mconfig->an_dailysettlement) < $settlementtime) {
         set_config('an_dailysettlement', $settlementtime, 'enrol/authorize');
         mtrace("    daily cron; some cleanups and sending email to admins the count of pending orders expiring", ": ");
         $this->cron_daily();
         mtrace("done");
     }
     mtrace("    scheduled capture", ": ");
     if (empty($CFG->an_review) or !empty($CFG->an_test) or intval($CFG->an_capture_day) < 1 or !check_openssl_loaded()) {
         mtrace("disabled");
         return;
         // order review disabled or test mode or manual capture or openssl wasn't loaded.
     }
     $timediffcnf = $settlementtime - intval($CFG->an_capture_day) * $oneday;
     $select = "(status = '" . AN_STATUS_AUTH . "') AND (timecreated < '{$timediffcnf}') AND (timecreated > '{$timediff30}')";
     if (!($ordercount = count_records_select('enrol_authorize', $select))) {
         mtrace("no pending orders");
         return;
     }
     $eachconn = intval($mconfig->an_eachconnsecs);
     $eachconn = $eachconn > 60 ? 60 : ($eachconn <= 0 ? 3 : $eachconn);
     if ($ordercount * $eachconn + intval($mconfig->an_lastcron) > $timenow) {
         mtrace("blocked");
         return;
     }
     set_config('an_lastcron', $timenow, 'enrol/authorize');
     mtrace("    {$ordercount} orders are being processed now", ": ");
     $faults = '';
     $sendem = array();
     $elapsed = time();
     @set_time_limit(0);
     $this->log = "AUTHORIZE.NET AUTOCAPTURE CRON: " . userdate($timenow) . "\n";
     $lastcourseid = 0;
     for ($rs = get_recordset_select('enrol_authorize', $select, 'courseid'); $order = rs_fetch_next_record($rs);) {
         $message = '';
         $extra = NULL;
         if (AN_APPROVED == authorize_action($order, $message, $extra, AN_ACTION_PRIOR_AUTH_CAPTURE)) {
             if ($lastcourseid != $order->courseid) {
                 $lastcourseid = $order->courseid;
                 $course = get_record('course', 'id', $lastcourseid);
                 $role = get_default_course_role($course);
                 $context = get_context_instance(CONTEXT_COURSE, $lastcourseid);
             }
             $timestart = $timeend = 0;
             if ($course->enrolperiod) {
                 $timestart = $timenow;
                 $timeend = $order->settletime + $course->enrolperiod;
             }
             $user = get_record('user', 'id', $order->userid);
             if (role_assign($role->id, $user->id, 0, $context->id, $timestart, $timeend, 0, 'authorize')) {
                 $this->log .= "User({$user->id}) has been enrolled to course({$course->id}).\n";
                 if (!empty($CFG->enrol_mailstudents)) {
                     $sendem[] = $order->id;
                 }
             } else {
                 $faults .= "Error while trying to enrol " . fullname($user) . " in '{$course->fullname}' \n";
                 foreach ($order as $okey => $ovalue) {
                     $faults .= "   {$okey} = {$ovalue}\n";
                 }
             }
         } else {
             $this->log .= "Error, Order# {$order->id}: " . $message . "\n";
         }
     }
     rs_close($rs);
     mtrace("processed");
     $timenow = time();
     $elapsed = $timenow - $elapsed;
     $eachconn = ceil($elapsed / $ordercount);
     set_config('an_eachconnsecs', $eachconn, 'enrol/authorize');
     $this->log .= "AUTHORIZE.NET CRON FINISHED: " . userdate($timenow);
     $adminuser = get_admin();
     if (!empty($faults)) {
         email_to_user($adminuser, $adminuser, "AUTHORIZE.NET CRON FAULTS", $faults);
     }
     if (!empty($CFG->enrol_mailadmins)) {
         email_to_user($adminuser, $adminuser, "AUTHORIZE.NET CRON LOG", $this->log);
     }
     // Send emails to students about which courses have enrolled.
     if (!empty($sendem)) {
         mtrace("    sending welcome messages to students", ": ");
         send_welcome_messages($sendem);
         mtrace("sent");
     }
 }
Пример #28
0
/**
 * Function to be run periodically according to the moodle cron
 * Mails new conversations out to participants, checks for any new
 * participants, and cleans up expired/closed conversations
 * @return   bool   true when complete
 */
function dialogue_cron()
{
    global $CFG, $USER;
    $context_cache = array();
    // delete any closed conversations which have expired
    dialogue_delete_expired_conversations();
    // Finds all dialogue entries that have yet to be mailed out, and mails them
    $sql = "SELECT e.* FROM {$CFG->prefix}dialogue_entries e " . "INNER JOIN {$CFG->prefix}dialogue d ON e.dialogueid = d.id " . "WHERE e.timecreated + d.edittime * 60 < " . time() . " AND e.mailed = 0 ";
    if ($entries = get_records_sql($sql)) {
        foreach ($entries as $entry) {
            echo "Processing dialogue entry {$entry->id}\n";
            if (!($userfrom = get_record('user', 'id', $entry->userid))) {
                mtrace("Could not find user {$entry->userid}\n");
                continue;
            }
            // get conversation record
            if (!($conversation = get_record('dialogue_conversations', 'id', $entry->conversationid))) {
                mtrace("Could not find conversation {$entry->conversationid}\n");
            }
            if ($userfrom->id == $conversation->userid) {
                if (!($userto = get_record('user', 'id', $conversation->recipientid))) {
                    mtrace("Could not find use {$conversation->recipientid}\n");
                }
            } else {
                if (!($userto = get_record('user', 'id', $conversation->userid))) {
                    mtrace("Could not find use {$conversation->userid}\n");
                }
            }
            $USER->lang = $userto->lang;
            if (!($dialogue = get_record('dialogue', 'id', $conversation->dialogueid))) {
                echo "Could not find dialogue id {$conversation->dialogueid}\n";
                continue;
            }
            if (!($course = get_record('course', 'id', $dialogue->course))) {
                echo "Could not find course {$dialogue->course}\n";
                continue;
            }
            if (!($cm = get_coursemodule_from_instance('dialogue', $dialogue->id, $course->id))) {
                echo "Course Module ID was incorrect\n";
            }
            if (empty($context_cache[$course->id])) {
                $context_cache[$course->id] = get_context_instance(CONTEXT_COURSE, $course->id);
            }
            if (!has_capability('mod/dialogue:participate', $context_cache[$course->id], $userfrom->id) && !has_capability('mod/dialogue:manage', $context_cache[$course->id], $userfrom->id)) {
                set_field('dialogue_entries', 'mailed', '1', 'id', $entry->id);
                continue;
                // Not an active participant
            }
            if (!has_capability('mod/dialogue:participate', $context_cache[$course->id], $userto->id) && !has_capability('mod/dialogue:manage', $context_cache[$course->id], $userto->id)) {
                set_field('dialogue_entries', 'mailed', '1', 'id', $entry->id);
                continue;
                // Not an active participant
            }
            $strdialogues = get_string('modulenameplural', 'dialogue');
            $strdialogue = get_string('modulename', 'dialogue');
            $dialogueinfo = new object();
            $dialogueinfo->userfrom = fullname($userfrom);
            $dialogueinfo->dialogue = format_string($dialogue->name);
            $dialogueinfo->url = "{$CFG->wwwroot}/mod/dialogue/view.php?id={$cm->id}";
            $postsubject = "{$course->shortname}: {$strdialogues}: {$dialogueinfo->dialogue}: " . get_string('newentry', 'dialogue');
            $posttext = "{$course->shortname} -> {$strdialogues} -> {$dialogueinfo->dialogue}\n";
            $posttext .= "---------------------------------------------------------------------\n";
            $posttext .= get_string('dialoguemail', 'dialogue', $dialogueinfo) . " \n";
            $posttext .= "---------------------------------------------------------------------\n";
            if ($userto->mailformat == 1) {
                // HTML
                $posthtml = "<p><font face=\"sans-serif\">" . "<a href=\"{$CFG->wwwroot}/course/view.php?id={$course->id}\">{$course->shortname}</a> ->" . "<a href=\"{$CFG->wwwroot}/mod/dialogue/index.php?id={$course->id}\">dialogues</a> ->" . "<a href=\"{$CFG->wwwroot}/mod/dialogue/view.php?id={$cm->id}\">" . $dialogueinfo->dialogue . "</a></font></p>";
                $posthtml .= "<hr /><font face=\"sans-serif\">";
                $posthtml .= '<p>' . get_string('dialoguemailhtml', 'dialogue', $dialogueinfo) . '</p>';
                $posthtml .= "</font><hr />";
            } else {
                $posthtml = '';
            }
            if (!email_to_user($userto, $userfrom, $postsubject, $posttext, $posthtml)) {
                mtrace("Error: dialogue cron: Could not send out mail for id {$entry->id} to user {$userto->id} ({$userto->email})\n");
            }
            if (!set_field('dialogue_entries', 'mailed', '1', 'id', $entry->id)) {
                mtrace("Could not update the mailed field for id {$entry->id}\n");
            }
        }
    }
    /// Find conversations sent to all participants and check for new participants
    $rs = get_recordset_select('dialogue_conversations', 'grouping != 0 AND grouping IS NOT NULL', 'dialogueid, grouping');
    $dialogueid = 0;
    $grouping = 0;
    $groupid = null;
    $inconversation = array();
    $newusers = array();
    while ($conversation = rs_fetch_next_record($rs)) {
        if ($dialogueid != $conversation->dialogueid || $groupid != $conversation->groupid || $grouping != $conversation->grouping) {
            if ($dialogueid == 0 || $groupid === null) {
                $dialogueid = $conversation->dialogueid;
                $groupid = $conversation->groupid;
            }
            $cm = get_coursemodule_from_instance('dialogue', $dialogueid);
            $context = get_context_instance(CONTEXT_MODULE, $cm->id);
            $users = (array) get_users_by_capability($context, 'mod/dialogue:participate', 'u.id, u.firstname, u.lastname', null, null, null, empty($groupid) ? null : $groupid, null, null, null, false);
            $managers = (array) get_users_by_capability($context, 'mod/dialogue:manage', 'u.id, u.firstname, u.lastname', null, null, null, null, null, null, null, false);
            $dialogueid = $conversation->dialogueid;
            $groupid = $conversation->groupid;
        }
        if ($grouping != $conversation->grouping) {
            if ($grouping) {
                if ($userdiff = array_diff_key($users, $inconversation, $managers)) {
                    foreach ($userdiff as $userid => $value) {
                        $newusers[$userid . ',' . $grouping] = array('userid' => $userid, 'courseid' => $cm->course, 'grouping' => $grouping);
                    }
                }
            }
            $inconversation = array();
            $grouping = $conversation->grouping;
        }
        $inconversation[$conversation->recipientid] = true;
    }
    if (!empty($dialogueid)) {
        // Finish of any remaing users
        $cm = get_coursemodule_from_instance('dialogue', $dialogueid);
        $context = get_context_instance(CONTEXT_MODULE, $cm->id);
        $users = (array) get_users_by_capability($context, 'mod/dialogue:participate', 'u.id, u.firstname, u.lastname', null, null, null, empty($groupid) ? null : $groupid, null, null, null, false);
        $managers = (array) get_users_by_capability($context, 'mod/dialogue:manage', 'u.id, u.firstname, u.lastname', null, null, null, null, null, null, null, false);
        if ($userdiff = array_diff_key($users, $inconversation, $managers)) {
            foreach ($userdiff as $userid => $value) {
                $newusers[$userid . ',' . $grouping] = array('userid' => $userid, 'courseid' => $cm->course, 'grouping' => $grouping);
            }
        }
    }
    rs_close($rs);
    if (!empty($newusers)) {
        foreach ($newusers as $key => $newuser) {
            begin_sql();
            course_setup($newuser['courseid']);
            if ($conversations = get_records('dialogue_conversations', 'grouping', $newuser['grouping'], 'id', '*', 0, 1)) {
                $conversation = array_pop($conversations);
                // we only need one to get the common field values
                if ($entry = get_records('dialogue_entries', 'conversationid', $conversation->id, 'id', '*', 0, 1)) {
                    unset($conversation->id);
                    $conversation->recipientid = $newuser['userid'];
                    $conversation->lastrecipientid = $newuser['userid'];
                    $conversation->timemodified = time();
                    $conversation->seenon = false;
                    $conversation->closed = 0;
                    $conversation = addslashes_object($conversation);
                    if (!($conversationid = insert_record('dialogue_conversations', $conversation))) {
                        rollback_sql();
                        continue;
                    }
                    $entry = array_pop($entry);
                    $srcentry = clone $entry;
                    unset($entry->id);
                    $entry->conversationid = $conversationid;
                    $entry->timecreated = $conversation->timemodified;
                    $entry->recipientid = $conversation->recipientid;
                    $entry->mailed = false;
                    $entry = addslashes_object($entry);
                    if (!($entry->id = insert_record('dialogue_entries', $entry))) {
                        rollback_sql();
                        continue;
                    }
                    $read = new stdClass();
                    $lastread = time();
                    $read->conversationid = $conversationid;
                    $read->entryid = $entry->id;
                    $read->userid = $conversation->userid;
                    $read->firstread = $lastread;
                    $read->lastread = $lastread;
                    insert_record('dialogue_read', $read);
                    if ($entry->attachment) {
                        $srcdir = dialogue_file_area($srcentry);
                        $dstdir = dialogue_file_area($entry);
                        copy($srcdir . '/' . $entry->attachment, $dstdir . '/' . $entry->attachment);
                    }
                } else {
                    mtrace('Failed to find entry for conversation: ' . $conversation->id);
                }
            } else {
                mtrace('Failed to find conversation: ' . $conversation->id);
            }
            commit_sql();
        }
    }
    return true;
}
Пример #29
0
 /**
 * Notify users about enrolments that are going to expire soon!
 * This function is run by admin/cron.php
 * @return void
 */
 function cron()
 {
     global $CFG, $USER, $SITE;
     if (!isset($CFG->lastexpirynotify)) {
         set_config('lastexpirynotify', 0);
     }
     // notify once a day only - TODO: add some tz handling here, maybe use timestamps
     if ($CFG->lastexpirynotify == date('Ymd')) {
         return;
     }
     if ($rs = get_recordset_select('course', 'enrolperiod > 0 AND expirynotify > 0 AND expirythreshold > 0')) {
         $cronuser = clone $USER;
         $admin = get_admin();
         while ($course = rs_fetch_next_record($rs)) {
             $a = new object();
             $a->coursename = $course->shortname . '/' . $course->fullname;
             // must be processed by format_string later
             $a->threshold = $course->expirythreshold / 86400;
             $a->extendurl = $CFG->wwwroot . '/user/index.php?id=' . $course->id;
             $a->current = array();
             $a->past = array();
             $expiry = time() + $course->expirythreshold;
             $cname = $course->fullname;
             /// Get all the manual role assignments for this course that have expired.
             if (!($context = get_context_instance(CONTEXT_COURSE, $course->id))) {
                 continue;
             }
             if ($oldenrolments = get_records_sql("\n                      SELECT u.*, ra.timeend\n                        FROM {$CFG->prefix}user u\n                             JOIN {$CFG->prefix}role_assignments ra ON (ra.userid = u.id)\n                        WHERE ra.contextid = {$context->id}\n                              AND ra.timeend > 0 AND ra.timeend <= {$expiry}\n                              AND ra.enrol = 'manual'")) {
                 // inform user who can assign roles or admin
                 if ($teachers = get_users_by_capability($context, 'moodle/role:assign', '', '', '', '', '', '', false)) {
                     $teachers = sort_by_roleassignment_authority($teachers, $context);
                     $teacher = reset($teachers);
                 } else {
                     $teachers = array($admin);
                     $teacher = $admin;
                 }
                 $a->teacherstr = fullname($teacher, true);
                 foreach ($oldenrolments as $user) {
                     /// Email all users about to expire
                     $a->studentstr = fullname($user, true);
                     if ($user->timeend < $expiry - 86400) {
                         $a->past[] = fullname($user) . " <{$user->email}>";
                     } else {
                         $a->current[] = fullname($user) . " <{$user->email}>";
                         if ($course->notifystudents) {
                             // Send this guy notice
                             // setup global $COURSE properly - needed for languages
                             $USER = $user;
                             course_setup($course);
                             $a->coursename = format_string($cname);
                             $a->course = $a->coursename;
                             $strexpirynotifystudentsemail = get_string('expirynotifystudentsemail', '', $a);
                             $strexpirynotify = get_string('expirynotify');
                             email_to_user($user, $teacher, format_string($SITE->fullname) . ' ' . $strexpirynotify, $strexpirynotifystudentsemail);
                         }
                     }
                 }
                 $a->current = implode("\n", $a->current);
                 $a->past = implode("\n", $a->past);
                 if ($a->current || $a->past) {
                     foreach ($teachers as $teacher) {
                         // setup global $COURSE properly - needed for languages
                         $USER = $teacher;
                         course_setup($course);
                         $a->coursename = format_string($cname);
                         $strexpirynotifyemail = get_string('expirynotifyemail', '', $a);
                         $strexpirynotify = get_string('expirynotify');
                         email_to_user($teacher, $admin, $a->coursename . ' ' . $strexpirynotify, $strexpirynotifyemail);
                     }
                 }
             }
         }
         $USER = $cronuser;
         course_setup($SITE);
         // More environment
     }
     set_config('lastexpirynotify', date('Ymd'));
 }
Пример #30
0
/**
 * Function to be run periodically according to the moodle cron
 * Finds all posts that have yet to be mailed out, and mails them
 * out to all subscribers
 * @return void
 */
function forum_cron()
{
    global $CFG, $USER;
    $cronuser = clone $USER;
    $site = get_site();
    // all users that are subscribed to any post that needs sending
    $users = array();
    // status arrays
    $mailcount = array();
    $errorcount = array();
    // caches
    $discussions = array();
    $forums = array();
    $courses = array();
    $coursemodules = array();
    $subscribedusers = 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
    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 = get_record('forum_discussions', 'id', $post->discussion)) {
                    $discussions[$discussionid] = $discussion;
                } else {
                    mtrace('Could not find discussion ' . $discussionid);
                    unset($posts[$pid]);
                    continue;
                }
            }
            $forumid = $discussions[$discussionid]->forum;
            if (!isset($forums[$forumid])) {
                if ($forum = get_record('forum', '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 = get_record('course', '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 course module for forum ' . $forumid);
                    unset($posts[$pid]);
                    continue;
                }
            }
            // caching subscribed users of each forum
            if (!isset($subscribedusers[$forumid])) {
                if ($subusers = forum_subscribed_users($courses[$courseid], $forums[$forumid], 0, false)) {
                    foreach ($subusers as $postuser) {
                        // do not try to mail users with stopped email
                        if ($postuser->emailstop) {
                            if (!empty($CFG->forum_logblocked)) {
                                add_to_log(SITEID, 'forum', 'mail blocked', '', '', 0, $postuser->id);
                            }
                            continue;
                        }
                        // this user is subscribed to this forum
                        $subscribedusers[$forumid][$postuser->id] = $postuser->id;
                        // this user is a user we have to process later
                        $users[$postuser->id] = $postuser;
                    }
                    unset($subusers);
                    // release memory
                }
            }
            $mailcount[$pid] = 0;
            $errorcount[$pid] = 0;
        }
    }
    if ($users && $posts) {
        $urlinfo = parse_url($CFG->wwwroot);
        $hostname = $urlinfo['host'];
        foreach ($users as $userto) {
            @set_time_limit(120);
            // terminate if processing of any account takes longer than 2 minutes
            // set this so that the capabilities are cached, and environment matches receiving user
            $USER = $userto;
            mtrace('Processing user ' . $userto->id);
            // init caches
            $userto->viewfullnames = array();
            $userto->canpost = array();
            $userto->markposts = array();
            $userto->enrolledin = array();
            // reset the caches
            foreach ($coursemodules as $forumid => $unused) {
                $coursemodules[$forumid]->cache = new object();
                $coursemodules[$forumid]->cache->caps = array();
                unset($coursemodules[$forumid]->uservisible);
            }
            foreach ($posts as $pid => $post) {
                // Set up the environment for the post, discussion, forum, course
                $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
                if (!isset($subscribedusers[$forum->id][$userto->id])) {
                    continue;
                    // user does not subscribe to this forum
                }
                // Verify user is enrollend in course - if not do not send any email
                if (!isset($userto->enrolledin[$course->id])) {
                    $userto->enrolledin[$course->id] = has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $course->id));
                }
                if (!$userto->enrolledin[$course->id]) {
                    // oops - this user should not receive anything from this course
                    continue;
                }
                // Get info about the sending user
                if (array_key_exists($post->userid, $users)) {
                    // we might know him/her already
                    $userfrom = $users[$post->userid];
                } else {
                    if ($userfrom = get_record('user', 'id', $post->userid)) {
                        $users[$userfrom->id] = $userfrom;
                        // fetch only once, we can add it to user list, it will be skipped anyway
                    } else {
                        mtrace('Could not find user ' . $post->userid);
                        continue;
                    }
                }
                // setup global $COURSE properly - needed for roles and languages
                course_setup($course);
                // More environment
                // Fill caches
                if (!isset($userto->viewfullnames[$forum->id])) {
                    $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
                    $userto->viewfullnames[$forum->id] = has_capability('moodle/site:viewfullnames', $modcontext);
                }
                if (!isset($userto->canpost[$discussion->id])) {
                    $modcontext = get_context_instance(CONTEXT_MODULE, $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();
                        $users[$userfrom->id]->groups = array();
                    }
                    $userfrom->groups[$forum->id] = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
                    $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
                        continue;
                        // Be safe and don't send it to anyone
                    }
                    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 it...
                if (!forum_user_can_see_post($forum, $discussion, $post, NULL, $cm)) {
                    mtrace('user ' . $userto->id . ' can not see ' . $post->id);
                    continue;
                }
                // OK so we need to send the email.
                // Does the user want this post in a digest?  If so postpone it for now.
                if ($userto->maildigest > 0) {
                    // This user wants the mails to be in digest form
                    $queue = new object();
                    $queue->userid = $userto->id;
                    $queue->discussionid = $discussion->id;
                    $queue->postid = $post->id;
                    $queue->timemodified = $post->created;
                    if (!insert_record('forum_queue', $queue)) {
                        mtrace("Error: mod/forum/cron.php: Could not queue for digest mail for id {$post->id} to user {$userto->id} ({$userto->email}) .. not trying again.");
                    }
                    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('Precedence: Bulk', 'List-Id: "' . $cleanforumname . '" <moodleforum' . $forum->id . '@' . $hostname . '>', 'List-Help: ' . $CFG->wwwroot . '/mod/forum/view.php?f=' . $forum->id, 'Message-ID: <moodlepost' . $post->id . '@' . $hostname . '>', 'In-Reply-To: <moodlepost' . $post->parent . '@' . $hostname . '>', 'References: <moodlepost' . $post->parent . '@' . $hostname . '>', 'X-Course-Id: ' . $course->id, 'X-Course-Name: ' . format_string($course->fullname, true));
                $postsubject = "{$course->shortname}: " . format_string($post->subject, true);
                $posttext = forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto);
                $posthtml = forum_make_mail_html($course, $forum, $discussion, $post, $userfrom, $userto);
                // Send the post now!
                mtrace('Sending ', '');
                if (!($mailresult = email_to_user($userto, $userfrom, $postsubject, $posttext, $posthtml, '', '', $CFG->forum_replytouser))) {
                    mtrace("Error: mod/forum/cron.php: Could not send out mail for id {$post->id} to user {$userto->id}" . " ({$userto->email}) .. not trying again.");
                    add_to_log($course->id, 'forum', 'mail error', "discuss.php?d={$discussion->id}#p{$post->id}", substr(format_string($post->subject, true), 0, 30), $cm->id, $userto->id);
                    $errorcount[$post->id]++;
                } else {
                    if ($mailresult === 'emailstop') {
                        // should not be reached anymore - see check above
                    } 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
            forum_tp_mark_posts_read($userto, $userto->markposts);
        }
    }
    if ($posts) {
        foreach ($posts as $post) {
            mtrace($mailcount[$post->id] . " users were sent post {$post->id}, '{$post->subject}'");
            if ($errorcount[$post->id]) {
                set_field("forum_posts", "mailed", "2", "id", "{$post->id}");
            }
        }
    }
    // release some memory
    unset($subscribedusers);
    unset($mailcount);
    unset($errorcount);
    $USER = clone $cronuser;
    course_setup(SITEID);
    $sitetimezone = $CFG->timezone;
    // Now see if there are any digest mails waiting to be sent, and if we should send them
    mtrace('Starting digest processing...');
    @set_time_limit(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;
    delete_records_select('forum_queue', "timemodified < {$weekago}");
    mtrace('Cleaned old digest records');
    if ($CFG->digestmailtimelast < $digesttime and $timenow > $digesttime) {
        mtrace('Sending forum digests: ' . userdate($timenow, '', $sitetimezone));
        $digestposts_rs = get_recordset_select('forum_queue', "timemodified < {$digesttime}");
        if (!rs_EOF($digestposts_rs)) {
            // We have work to do
            $usermailcount = 0;
            //caches - reuse the those filled before too
            $discussionposts = array();
            $userdiscussions = array();
            while ($digestpost = rs_fetch_next_record($digestposts_rs)) {
                if (!isset($users[$digestpost->userid])) {
                    if ($user = get_record('user', 'id', $digestpost->userid)) {
                        $users[$digestpost->userid] = $user;
                    } else {
                        continue;
                    }
                }
                $postuser = $users[$digestpost->userid];
                if ($postuser->emailstop) {
                    if (!empty($CFG->forum_logblocked)) {
                        add_to_log(SITEID, 'forum', 'mail blocked', '', '', 0, $postuser->id);
                    }
                    continue;
                }
                if (!isset($posts[$digestpost->postid])) {
                    if ($post = get_record('forum_posts', 'id', $digestpost->postid)) {
                        $posts[$digestpost->postid] = $post;
                    } else {
                        continue;
                    }
                }
                $discussionid = $digestpost->discussionid;
                if (!isset($discussions[$discussionid])) {
                    if ($discussion = get_record('forum_discussions', 'id', $discussionid)) {
                        $discussions[$discussionid] = $discussion;
                    } else {
                        continue;
                    }
                }
                $forumid = $discussions[$discussionid]->forum;
                if (!isset($forums[$forumid])) {
                    if ($forum = get_record('forum', 'id', $forumid)) {
                        $forums[$forumid] = $forum;
                    } else {
                        continue;
                    }
                }
                $courseid = $forums[$forumid]->course;
                if (!isset($courses[$courseid])) {
                    if ($course = get_record('course', '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;
            }
            rs_close($digestposts_rs);
            /// Finished iteration, let's close the resultset
            // Data collected, start sending out emails to each user
            foreach ($userdiscussions as $userid => $thesediscussions) {
                @set_time_limit(120);
                // terminate if processing of any account takes longer than 2 minutes
                $USER = $cronuser;
                course_setup(SITEID);
                // reset cron user language, theme and timezone settings
                mtrace(get_string('processingdigest', 'forum', $userid), '... ');
                // First of all delete all the queue entries for this user
                delete_records_select('forum_queue', "userid = {$userid} AND timemodified < {$digesttime}");
                $userto = $users[$userid];
                // Override the language and timezone of the "current" user, so that
                // mail is customised for the receiver.
                $USER = $userto;
                course_setup(SITEID);
                // init caches
                $userto->viewfullnames = array();
                $userto->canpost = array();
                $userto->markposts = array();
                $postsubject = get_string('digestmailsubject', 'forum', format_string($site->shortname, true));
                $headerdata = new object();
                $headerdata->sitename = format_string($site->fullname, true);
                $headerdata->userprefs = $CFG->wwwroot . '/user/edit.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 = "<head>";
                foreach ($CFG->stylesheets as $stylesheet) {
                    $posthtml .= '<link rel="stylesheet" type="text/css" href="' . $stylesheet . '" />' . "\n";
                }
                $posthtml .= "</head>\n<body id=\"email\">\n";
                $posthtml .= '<p>' . get_string('digestmailheader', 'forum', $headerdata) . '</p><br /><hr size="1" noshade="noshade" />';
                foreach ($thesediscussions as $discussionid) {
                    @set_time_limit(120);
                    // to be reset for each post
                    $discussion = $discussions[$discussionid];
                    $forum = $forums[$discussion->forum];
                    $course = $courses[$forum->course];
                    $cm = $coursemodules[$forum->id];
                    //override language
                    course_setup($course);
                    // Fill caches
                    if (!isset($userto->viewfullnames[$forum->id])) {
                        $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
                        $userto->viewfullnames[$forum->id] = has_capability('moodle/site:viewfullnames', $modcontext);
                    }
                    if (!isset($userto->canpost[$discussion->id])) {
                        $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
                        $userto->canpost[$discussion->id] = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
                    }
                    $strforums = get_string('forums', 'forum');
                    $canunsubscribe = !forum_is_forcesubscribed($forum);
                    $canreply = $userto->canpost[$discussion->id];
                    $posttext .= "\n \n";
                    $posttext .= '=====================================================================';
                    $posttext .= "\n \n";
                    $posttext .= "{$course->shortname} -> {$strforums} -> " . format_string($forum->name, true);
                    if ($discussion->name != $forum->name) {
                        $posttext .= " -> " . format_string($discussion->name, true);
                    }
                    $posttext .= "\n";
                    $posthtml .= "<p><font face=\"sans-serif\">" . "<a target=\"_blank\" href=\"{$CFG->wwwroot}/course/view.php?id={$course->id}\">{$course->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);
                    foreach ($postsarray as $postid) {
                        $post = $posts[$postid];
                        if (array_key_exists($post->userid, $users)) {
                            // we might know him/her already
                            $userfrom = $users[$post->userid];
                        } else {
                            if ($userfrom = get_record('user', 'id', $post->userid)) {
                                $users[$userfrom->id] = $userfrom;
                                // fetch only once, we can add it to user list, it will be skipped anyway
                            } else {
                                mtrace('Could not find user ' . $post->userid);
                                continue;
                            }
                        }
                        if (!isset($userfrom->groups[$forum->id])) {
                            if (!isset($userfrom->groups)) {
                                $userfrom->groups = array();
                                $users[$userfrom->id]->groups = array();
                            }
                            $userfrom->groups[$forum->id] = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
                            $users[$userfrom->id]->groups[$forum->id] = $userfrom->groups[$forum->id];
                        }
                        $userfrom->customheaders = array("Precedence: Bulk");
                        if ($userto->maildigest == 2) {
                            // Subjects only
                            $by = new object();
                            $by->name = fullname($userfrom);
                            $by->date = userdate($post->modified);
                            $posttext .= "\n" . format_string($post->subject, true) . ' ' . get_string("bynameondate", "forum", $by);
                            $posttext .= "\n---------------------------------------------------------------------";
                            $by->name = "<a target=\"_blank\" href=\"{$CFG->wwwroot}/user/view.php?id={$userfrom->id}&amp;course={$course->id}\">{$by->name}</a>";
                            $posthtml .= '<div><a target="_blank" href="' . $CFG->wwwroot . '/mod/forum/discuss.php?d=' . $discussion->id . '#p' . $post->id . '">' . format_string($post->subject, true) . '</a> ' . get_string("bynameondate", "forum", $by) . '</div>';
                        } else {
                            // The full treatment
                            $posttext .= forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto, true);
                            $posthtml .= forum_make_mail_post($course, $forum, $discussion, $post, $userfrom, $userto, false, $canreply, true, false);
                            // Create an array of postid's for this user to mark as read.
                            if (!$CFG->forum_usermarksread) {
                                $userto->markposts[$post->id] = $post->id;
                            }
                        }
                    }
                    if ($canunsubscribe) {
                        $posthtml .= "\n<div align=\"right\"><font size=\"1\"><a href=\"{$CFG->wwwroot}/mod/forum/subscribe.php?id={$forum->id}\">" . get_string("unsubscribe", "forum") . "</a></font></div>";
                    } else {
                        $posthtml .= "\n<div align=\"right\"><font size=\"1\">" . get_string("everyoneissubscribed", "forum") . "</font></div>";
                    }
                    $posthtml .= '<hr size="1" noshade="noshade" /></p>';
                }
                $posthtml .= '</body>';
                if ($userto->mailformat != 1) {
                    // This user DOESN'T want to receive HTML
                    $posthtml = '';
                }
                if (!($mailresult = email_to_user($userto, $site->shortname, $postsubject, $posttext, $posthtml, '', '', $CFG->forum_replytouser))) {
                    mtrace("ERROR!");
                    echo "Error: mod/forum/cron.php: Could not send out digest mail to user {$userto->id} ({$userto->email})... not trying again.\n";
                    add_to_log($course->id, 'forum', 'mail digest error', '', '', $cm->id, $userto->id);
                } else {
                    if ($mailresult === 'emailstop') {
                        // should not happen anymore - see check above
                    } else {
                        mtrace("success.");
                        $usermailcount++;
                        // Mark post as read if forum_usermarksread is set off
                        forum_tp_mark_posts_read($userto, $userto->markposts);
                    }
                }
            }
        }
        /// We have finishied all digest emails, update $CFG->digestmailtimelast
        set_config('digestmailtimelast', $timenow);
    }
    $USER = $cronuser;
    course_setup(SITEID);
    // reset cron user language, theme and timezone settings
    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;
}