/mod/forum/lib.php
PHP | 6976 lines | 5155 code | 992 blank | 829 comment | 1034 complexity | c8d63c1982e7b59eb17a68b8404fb675 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- <?php // $Id$
-
- require_once($CFG->libdir.'/filelib.php');
-
- /// CONSTANTS ///////////////////////////////////////////////////////////
-
- define('FORUM_MODE_FLATOLDEST', 1);
- define('FORUM_MODE_FLATNEWEST', -1);
- define('FORUM_MODE_THREADED', 2);
- define('FORUM_MODE_NESTED', 3);
-
- define('FORUM_FORCESUBSCRIBE', 1);
- define('FORUM_INITIALSUBSCRIBE', 2);
- define('FORUM_DISALLOWSUBSCRIBE',3);
-
- define('FORUM_TRACKING_OFF', 0);
- define('FORUM_TRACKING_OPTIONAL', 1);
- define('FORUM_TRACKING_ON', 2);
-
- define('FORUM_UNSET_POST_RATING', -999);
-
- define ('FORUM_AGGREGATE_NONE', 0); //no ratings
- define ('FORUM_AGGREGATE_AVG', 1);
- define ('FORUM_AGGREGATE_COUNT', 2);
- define ('FORUM_AGGREGATE_MAX', 3);
- define ('FORUM_AGGREGATE_MIN', 4);
- define ('FORUM_AGGREGATE_SUM', 5);
-
- /// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
-
- /**
- * Given an object containing all the necessary data,
- * (defined by the form in mod.html) this function
- * will create a new instance and return the id number
- * of the new instance.
- * @param object $forum add forum instance (with magic quotes)
- * @return int intance id
- */
- function forum_add_instance($forum) {
- global $CFG;
-
- $forum->timemodified = time();
-
- if (empty($forum->assessed)) {
- $forum->assessed = 0;
- }
-
- if (empty($forum->ratingtime) or empty($forum->assessed)) {
- $forum->assesstimestart = 0;
- $forum->assesstimefinish = 0;
- }
-
- if (!$forum->id = insert_record('forum', $forum)) {
- return false;
- }
-
- if ($forum->type == 'single') { // Create related discussion.
- $discussion = new object();
- $discussion->course = $forum->course;
- $discussion->forum = $forum->id;
- $discussion->name = $forum->name;
- $discussion->intro = $forum->intro;
- $discussion->assessed = $forum->assessed;
- $discussion->format = $forum->type;
- $discussion->mailnow = false;
- $discussion->groupid = -1;
-
- if (! forum_add_discussion($discussion, $discussion->intro)) {
- error('Could not add the discussion for this forum');
- }
- }
-
- if ($forum->forcesubscribe == FORUM_INITIALSUBSCRIBE) {
- /// all users should be subscribed initially
- /// Note: forum_get_potential_subscribers should take the forum context,
- /// but that does not exist yet, becuase the forum is only half build at this
- /// stage. However, because the forum is brand new, we know that there are
- /// no role assignments or overrides in the forum context, so using the
- /// course context gives the same list of users.
- $users = forum_get_potential_subscribers(get_context_instance(CONTEXT_COURSE, $forum->course), 0, 'u.id, u.email', '');
- foreach ($users as $user) {
- forum_subscribe($user->id, $forum->id);
- }
- }
-
- $forum = stripslashes_recursive($forum);
- forum_grade_item_update($forum);
-
- return $forum->id;
- }
-
-
- /**
- * Given an object containing all the necessary data,
- * (defined by the form in mod.html) this function
- * will update an existing instance with new data.
- * @param object $forum forum instance (with magic quotes)
- * @return bool success
- */
- function forum_update_instance($forum) {
- global $USER;
-
- $forum->timemodified = time();
- $forum->id = $forum->instance;
-
- if (empty($forum->assessed)) {
- $forum->assessed = 0;
- }
-
- if (empty($forum->ratingtime) or empty($forum->assessed)) {
- $forum->assesstimestart = 0;
- $forum->assesstimefinish = 0;
- }
-
- $oldforum = get_record('forum', 'id', $forum->id);
-
- // MDL-3942 - if the aggregation type or scale (i.e. max grade) changes then recalculate the grades for the entire forum
- // if scale changes - do we need to recheck the ratings, if ratings higher than scale how do we want to respond?
- // for count and sum aggregation types the grade we check to make sure they do not exceed the scale (i.e. max score) when calculating the grade
- if (($oldforum->assessed<>$forum->assessed) or ($oldforum->scale<>$forum->scale)) {
- forum_update_grades($forum); // recalculate grades for the forum
- }
-
- if ($forum->type == 'single') { // Update related discussion and post.
- if (! $discussion = get_record('forum_discussions', 'forum', $forum->id)) {
- if ($discussions = get_records('forum_discussions', 'forum', $forum->id, 'timemodified ASC')) {
- notify('Warning! There is more than one discussion in this forum - using the most recent');
- $discussion = array_pop($discussions);
- } else {
- // try to recover by creating initial discussion - MDL-16262
- $discussion = new object();
- $discussion->course = $forum->course;
- $discussion->forum = $forum->id;
- $discussion->name = $forum->name;
- $discussion->intro = $forum->intro;
- $discussion->assessed = $forum->assessed;
- $discussion->format = $forum->type;
- $discussion->mailnow = false;
- $discussion->groupid = -1;
-
- forum_add_discussion($discussion, $discussion->intro);
-
- if (! $discussion = get_record('forum_discussions', 'forum', $forum->id)) {
- error('Could not add the discussion for this forum');
- }
-
- }
- }
- if (! $post = get_record('forum_posts', 'id', $discussion->firstpost)) {
- error('Could not find the first post in this forum discussion');
- }
-
- $post->subject = $forum->name;
- $post->message = $forum->intro;
- $post->modified = $forum->timemodified;
- $post->userid = $USER->id; // MDL-18599, so that current teacher can take ownership of activities
-
- if (! update_record('forum_posts', ($post))) {
- error('Could not update the first post');
- }
-
- $discussion->name = $forum->name;
-
- if (! update_record('forum_discussions', ($discussion))) {
- error('Could not update the discussion');
- }
- }
-
- if (!update_record('forum', $forum)) {
- error('Can not update forum');
- }
-
- $forum = stripslashes_recursive($forum);
- forum_grade_item_update($forum);
-
- return true;
- }
-
-
- /**
- * Given an ID of an instance of this module,
- * this function will permanently delete the instance
- * and any data that depends on it.
- * @param int forum instance id
- * @return bool success
- */
- function forum_delete_instance($id) {
-
- if (!$forum = get_record('forum', 'id', $id)) {
- return false;
- }
-
- $result = true;
-
- if ($discussions = get_records('forum_discussions', 'forum', $forum->id)) {
- foreach ($discussions as $discussion) {
- if (!forum_delete_discussion($discussion, true)) {
- $result = false;
- }
- }
- }
-
- if (!delete_records('forum_subscriptions', 'forum', $forum->id)) {
- $result = false;
- }
-
- forum_tp_delete_read_records(-1, -1, -1, $forum->id);
-
- if (!delete_records('forum', 'id', $forum->id)) {
- $result = false;
- }
-
- forum_grade_item_delete($forum);
-
- return $result;
- }
-
-
- /**
- * 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])) {
- $modcontext = get_context_instance(CONTEXT_MODULE, $coursemodules[$forumid]->id);
- if ($subusers = forum_subscribed_users($courses[$courseid], $forums[$forumid], 0, $modcontext)) {
- 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;
- }
-
- // Don't send email if the forum is Q&A and the user has not posted
- if ($forum->type == 'qanda' && !forum_get_user_posted_time($discussion->id, $userto->id)) {
- mtrace('Did not email '.$userto->id.' because user has not posted in discussion');
- continue;
- }
-
- // Get info about the sending user
- if (array_key_exists($post->userid, $users)) { // we might know 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 ( // Headers to make emails easier to track
- '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.'>',
- 'X-Course-Id: '.$course->id,
- 'X-Course-Name: '.format_string($course->fullname, true)
- );
-
- if ($post->parent) { // This post is a reply, so add headers for threading (see MDL-22551)
- $userfrom->customheaders[] = 'In-Reply-To: <moodlepost'.$post->parent.'@'.$hostname.'>';
- $userfrom->customheaders[] = 'References: <moodlepost'.$post->parent.'@'.$hostname.'>';
- }
-
- $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.'&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&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 class='mdl-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 class='mdl-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;
- }
-
- /**
- * Builds and returns the body of the email notification in plain text.
- *
- * @param object $course
- * @param object $forum
- * @param object $discussion
- * @param object $post
- * @param object $userfrom
- * @param object $userto
- * @param boolean $bare
- * @return string The email body in plain text format.
- */
- function forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto, $bare = false) {
- global $CFG, $USER;
-
- if (!isset($userto->viewfullnames[$forum->id])) {
- if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
- error('Course Module ID was incorrect');
- }
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
- $viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
- } else {
- $viewfullnames = $userto->viewfullnames[$forum->id];
- }
-
- if (!isset($userto->canpost[$discussion->id])) {
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
- $canreply = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
- } else {
- $canreply = $userto->canpost[$discussion->id];
- }
-
- $by = New stdClass;
- $by->name = fullname($userfrom, $viewfullnames);
- $by->date = userdate($post->modified, "", $userto->timezone);
-
- $strbynameondate = get_string('bynameondate', 'forum', $by);
-
- $strforums = get_string('forums', 'forum');
-
- $canunsubscribe = ! forum_is_forcesubscribed($forum);
-
- $posttext = '';
-
- if (!$bare) {
- $posttext = "$course->shortname -> $strforums -> ".format_string($forum->name,true);
-
- if ($discussion->name != $forum->name) {
- $posttext .= " -> ".format_string($discussion->name,true);
- }
- }
-
- $posttext .= "\n---------------------------------------------------------------------\n";
- $posttext .= format_string($post->subject,true);
- if ($bare) {
- $posttext .= " ($CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id#p$post->id)";
- }
- $posttext .= "\n".$strbynameondate."\n";
- $posttext .= "---------------------------------------------------------------------\n";
- $posttext .= format_text_email(trusttext_strip($post->message), $post->format);
- $posttext .= "\n\n";
- if ($post->attachment) {
- $post->course = $course->id;
- $post->forum = $forum->id;
- $posttext .= forum_print_attachments($post, "text");
- }
- if (!$bare && $canreply) {
- $posttext .= "---------------------------------------------------------------------\n";
- $posttext .= get_string("postmailinfo", "forum", $course->shortname)."\n";
- $posttext .= "$CFG->wwwroot/mod/forum/post.php?reply=$post->id\n";
- }
- if (!$bare && $canunsubscribe) {
- $posttext .= "\n---------------------------------------------------------------------\n";
- $posttext .= get_string("unsubscribe", "forum");
- $posttext .= ": $CFG->wwwroot/mod/forum/subscribe.php?id=$forum->id\n";
- }
-
- return $posttext;
- }
-
- /**
- * Builds and returns the body of the email notification in html format.
- *
- * @param object $course
- * @param object $forum
- * @param object $discussion
- * @param object $post
- * @param object $userfrom
- * @param object $userto
- * @return string The email text in HTML format
- */
- function forum_make_mail_html($course, $forum, $discussion, $post, $userfrom, $userto) {
- global $CFG;
-
- if ($userto->mailformat != 1) { // Needs to be HTML
- return '';
- }
-
- if (!isset($userto->canpost[$discussion->id])) {
- $canreply = forum_user_can_post($forum, $discussion, $userto);
- } else {
- $canreply = $userto->canpost[$discussion->id];
- }
-
- $strforums = get_string('forums', 'forum');
- $canunsubscribe = ! forum_is_forcesubscribed($forum);
-
- $posthtml = '<head>';
- foreach ($CFG->stylesheets as $stylesheet) {
- $posthtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
- }
- $posthtml .= '</head>';
- $posthtml .= "\n<body id=\"email\">\n\n";
-
- $posthtml .= '<div class="navbar">'.
- '<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 .= '</div>';
- } else {
- $posthtml .= ' » <a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion->id.'">'.
- format_string($discussion->name,true).'</a></div>';
- }
- $posthtml .= forum_make_mail_post($course, $forum, $discussion, $post, $userfrom, $userto, false, $canreply, true, false);
-
- if ($canunsubscribe) {
- $posthtml .= '<hr /><div class="mdl-align unsubscribelink">
- <a href="'.$CFG->wwwroot.'/mod/forum/subscribe.php?id='.$forum->id.'">'.get_string('unsubscribe', 'forum').'</a>
- <a href="'.$CFG->wwwroot.'/mod/forum/unsubscribeall.php">'.get_string('unsubscribeall', 'forum').'</a></div>';
- }
-
- $posthtml .= '</body>';
-
- return $posthtml;
- }
-
-
- /**
- *
- * @param object $course
- * @param object $user
- * @param object $mod TODO this is not used in this function, refactor
- * @param object $forum
- * @return object A standard object with 2 variables: info (number of posts for this user) and time (last modified)
- */
- function forum_user_outline($course, $user, $mod, $forum) {
- global $CFG;
- require_once("$CFG->libdir/gradelib.php");
- $grades = grade_get_grades($course->id, 'mod', 'forum', $forum->id, $user->id);
- if (empty($grades->items[0]->grades)) {
- $grade = false;
- } else {
- $grade = reset($grades->items[0]->grades);
- }
-
- $count = forum_count_user_posts($forum->id, $user->id);
-
- if ($count && $count->postcount > 0) {
- $result = new object();
- $result->info = get_string("numposts", "forum", $count->postcount);
- $result->time = $count->lastpost;
- if ($grade) {
- $result->info .= ', ' . get_string('grade') . ': ' . $grade->str_long_grade;
- }
- return $result;
- } else if ($grade) {
- $result = new object();
- $result->info = get_string('grade') . ': ' . $grade->str_long_grade;
-
- //datesubmitted == time created. dategraded == time modified or time overridden
- //if grade was last modified by the user themselves use date graded. Otherwise use date submitted
- if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) {
- $result->time = $grade->dategraded;
- } else {
- $result->time = $grade->datesubmitted;
- }
-
- return $result;
- }
- return NULL;
- }
-
-
- /**
- *
- */
- function forum_user_complete($course, $user, $mod, $forum) {
- global $CFG,$USER;
- require_once("$CFG->libdir/gradelib.php");
-
- $grades = grade_get_grades($course->id, 'mod', 'forum', $forum->id, $user->id);
- if (!empty($grades->items[0]->grades)) {
- $grade = reset($grades->items[0]->grades);
- echo '<p>'.get_string('grade').': '.$grade->str_long_grade.'</p>';
- if ($grade->str_feedback) {
- echo '<p>'.get_string('feedback').': '.$grade->str_feedback.'</p>';
- }
- }
-
- if ($posts = forum_get_user_posts($forum->id, $user->id)) {
-
- if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
- error('Course Module ID was incorrect');
- }
- $discussions = forum_get_user_involved_discussions($forum->id, $user->id);
-
- // preload all user ratings for these discussions - one query only and minimal memory
- $cm->cache->ratings = array();
- $cm->cache->myratings = array();
- if ($postratings = forum_get_all_user_ratings($user->id, $discussions)) {
- foreach ($postratings as $pr) {
- if (!isset($cm->cache->ratings[$pr->postid])) {
- $cm->cache->ratings[$pr->postid] = array();
- }
- $cm->cache->ratings[$pr->postid][$pr->id] = $pr->rating;
-
- if ($pr->userid == $USER->id) {
- $cm->cache->myratings[$pr->postid] = $pr->rating;
- }
- }
- unset($postratings);
- }
-
- foreach ($posts as $post) {
- if (!isset($discussions[$post->discussion])) {
- continue;
- }
- $discussion = $discussions[$post->discussion];
-
- $ratings = null;
-
- if ($forum->assessed) {
- if ($scale = make_grades_menu($forum->scale)) {
- $ratings =new object();
- $ratings->scale = $scale;
- $ratings->assesstimestart = $forum->assesstimestart;
- $ratings->assesstimefinish = $forum->assesstimefinish;
- $ratings->allow = false;
- }
- }
-
- forum_print_post($post, $discussion, $forum, $cm, $course, false, false, false, $ratings);
-
- }
- } else {
- echo "<p>".get_string("noposts", "forum")."</p>";
- }
- }
-
-
- /**
- *
- */
- function forum_print_overview($courses,&$htmlarray) {
- global $USER, $CFG;
- //$LIKE = sql_ilike();//no longer using like in queries. MDL-20578
-
- if (empty($courses) || !is_array($courses) || count($courses) == 0) {
- return array();
- }
-
- if (!$forums = get_all_instances_in_courses('forum',$courses)) {
- return;
- }
-
-
- // get all forum logs in ONE query (much better!)
- $sql = "SELECT instance,cmid,l.course,COUNT(l.id) as count FROM {$CFG->prefix}log l "
- ." JOIN {$CFG->prefix}course_modules cm ON cm.id = cmid "
- ." WHERE (";
- foreach ($courses as $course) {
- $sql .= '(l.course = '.$course->id.' AND l.time > '.$course->lastaccess.') OR ';
- }
- $sql = substr($sql,0,-3); // take off the last OR
-
- $sql .= ") AND l.module = 'forum' AND action = 'add post' "
- ." AND userid != ".$USER->id." GROUP BY cmid,l.course,instance";
-
- if (!$new = get_records_sql($sql)) {
- $new = array(); // avoid warnings
- }
-
- // also get all forum tracking stuff ONCE.
- $trackingforums = array();
- foreach ($forums as $forum) {
- if (forum_tp_can_track_forums($forum)) {
- $trackingforums[$forum->id] = $forum;
- }
- }
-
- if (count($trackingforums) > 0) {
- $cutoffdate = isset($CFG->forum_oldpostdays) ? (time() - ($CFG->forum_oldpostdays*24*60*60)) : 0;
- $sql = 'SELECT d.forum,d.course,COUNT(p.id) AS count '.
- ' FROM '.$CFG->prefix.'forum_posts p '.
- ' JOIN '.$CFG->prefix.'forum_discussions d ON p.discussion = d.id '.
- ' LEFT JOIN '.$CFG->prefix.'forum_read r ON r.postid = p.id AND r.userid = '.$USER->id.' WHERE (';
- foreach ($trackingforums as $track) {
- $sql .= '(d.forum = '.$track->id.' AND (d.groupid = -1 OR d.groupid = 0 OR d.groupid = '.get_current_group($track->course).')) OR ';
- }
- $sql = substr($sql,0,-3); // take off the last OR
- $sql .= ') AND p.modified >= '.$cutoffdate.' AND r.id is NULL GROUP BY d.forum,d.course';
-
- if (!$unread = get_records_sql($sql)) {
- $unread = array();
- }
- } else {
- $unread = array();
- }
-
- if (empty($unread) and empty($new)) {
- return;
- }
-
- $strforum = get_string('modulename','forum');
- $strnumunread = get_string('overviewnumunread','forum');
- $strnumpostssince = get_string('overviewnumpostssince','forum');
-
- foreach ($forums as $forum) {
- $str = '';
- $count = 0;
- $thisunread = 0;
- $showunread = false;
- // either we have something from logs, or trackposts, or nothing.
- if (array_key_exists($forum->id, $new) && !empty($new[$forum->id])) {
- $count = $new[$forum->id]->count;
- }
- if (array_key_exists($forum->id,$unread)) {
- $thisunread = $unread[$forum->id]->count;
- $showunread = true;
- }
- if ($count > 0 || $thisunread > 0) {
- $str .= '<div class="overview forum"><div class="name">'.$strforum.': <a title="'.$strforum.'" href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'">'.
- $forum->name.'</a></div>';
- $str .= '<div class="info">';
- $str .= $count.' '.$strnumpostssince;
- if (!empty($showunread)) {
- $str .= '<br />'.$thisunread .' '.$strnumunread;
- }
- $str .= '</div></div>';
- }
- if (!empty($str)) {
- if (!array_key_exists($forum->course,$htmlarray)) {
- $htmlarray[$forum->course] = array();
- }
- if (!array_key_exists('forum',$htmlarray[$forum->course])) {
- $htmlarray[$forum->course]['forum'] = ''; // initialize, avoid warnings
- }
- $htmlarray[$forum->course]['forum'] .= $str;
- }
- }
- }
-
- /**
- * Given a course and a date, prints a summary of all the new
- * messages posted in the course since that date
- * @param object $course
- * @param bool $viewfullnames capability
- * @param int $timestart
- * @return bool success
- */
- function forum_print_recent_activity($course, $viewfullnames, $timestart) {
- global $CFG, $USER;
-
- // do not use log table if possible, it may be…
Large files files are truncated, but you can click here to view the full file