Index: moodle/lang/en_utf8/forum.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/lang/en_utf8/forum.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 forum.php --- moodle/lang/en_utf8/forum.php 31 Jan 2009 18:28:13 -0000 1.1.1.1 +++ moodle/lang/en_utf8/forum.php 29 Jan 2009 23:13:11 -0000 @@ -1,4 +1,4 @@ -name will NOT receive email copies of all posts to \'$a->forum\''; $string['nownottracking'] = '$a->name is no longer tracking \'$a->forum\'.'; $string['nowsubscribed'] = '$a->name will receive copies of \'$a->forum\' by email.'; $string['nowtracking'] = '$a->name is now tracking \'$a->forum\'.'; @@ -248,18 +264,30 @@ $string['seeallposts'] = 'See all posts made by this user'; $string['sendinratings'] = 'Send in my latest ratings'; $string['shortpost'] = 'Short post'; -$string['showsubscribers'] = 'Show/edit current subscribers'; +$string['showsubscribers'] = 'Show/edit current forum subscribers'; // Added by JWC : 'forum' $string['singleforum'] = 'A single simple discussion'; $string['startedby'] = 'Started by'; $string['subject'] = 'Subject'; $string['subscribe'] = 'Subscribe to this forum'; $string['subscribeall'] = 'Subscribe everyone to this forum'; $string['subscribed'] = 'Subscribed'; +// Added by JWC for threaded subscriptions +$string['subscribedthread'] = 'You are subscribed to this discussion thread'; +// Added by JWC for threaded subscriptions +$string['subscribedthreadno'] = 'You are NOT subscribed to this discussion thread'; +// Added by JWC for threaded subscriptions +$string['subscribedthreadq'] = 'Thread subscribed?'; $string['subscribenone'] = 'Unsubscribe everyone from this forum'; $string['subscribers'] = 'Subscribers'; $string['subscribersto'] = 'Subscribers to \'$a\''; $string['subscribestart'] = 'Send me email copies of posts to this forum'; +// Added by JWC for threaded subscriptions +$string['subscribestartthread'] = 'Send me email copies of posts to this discussion'; $string['subscribestop'] = 'I don\'t want email copies of posts to this forum'; +// Added by JWC for threaded subscriptions +$string['subscribestopthread'] = 'I don\'t want email copies of posts to this discussion'; +// Added by JWC for threaded subscriptions +$string['subscribethisthread'] = 'Subscribe to this discussion thread'; $string['subscription'] = 'Subscription'; $string['subscriptions'] = 'Subscriptions'; $string['thisforumisthrottled'] = 'This forum has a limit to the number of forum postings you can make in a given time period - this is currently set at $a->blockafter posting(s) in $a->blockperiod'; @@ -283,6 +311,8 @@ $string['unsubscribed'] = 'Unsubscribed'; $string['unsubscribedthread'] = 'Thread unsubscribed'; $string['unsubscribeshort'] = 'Unsubscribe'; +// Added by JWC for threaded subscriptions +$string['unsubscribethisthread'] = 'Unsubscribe from this discussion thread'; $string['usermarksread'] = 'Manual message read marking'; $string['warnafter'] = 'Post threshold for warning'; $string['yesforever'] = 'Yes, forever'; Index: moodle/lang/en_utf8/help/forum/subscription.html =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/lang/en_utf8/help/forum/subscription.html,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 subscription.html --- moodle/lang/en_utf8/help/forum/subscription.html 31 Jan 2009 18:29:41 -0000 1.1.1.1 +++ moodle/lang/en_utf8/help/forum/subscription.html 26 Jan 2009 10:46:06 -0000 @@ -14,4 +14,9 @@

This is especially useful in the News forum and in forums towards the beginning of the course (before everyone has -worked out that they can subscribe to these emails themselves).

\ No newline at end of file +worked out that they can subscribe to these emails themselves).

+ +

Further choices may be offered by the teacher allowing +subscription by discussion thread. When subscribed to a thread +the user gets email copies of posts in that thread only. +In very large forums this may be more appropriate.

\ No newline at end of file Index: moodle/lang/en_utf8/help/forum/subscription2.html =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/lang/en_utf8/help/forum/subscription2.html,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 subscription2.html --- moodle/lang/en_utf8/help/forum/subscription2.html 31 Jan 2009 18:29:44 -0000 1.1.1.1 +++ moodle/lang/en_utf8/help/forum/subscription2.html 28 Jan 2009 13:59:19 -0000 @@ -31,4 +31,17 @@ existing users, it will only affect future course users. Similarly changing later to "Yes, initially" will not subscribe existing course users but only those enrolling later. +

+ +

"Allow thread or forum subscriptions" lets the user choose whether or +not to subscribe, and whether to subscribe to distinct discussion threads +or the entire forum, whereas "Automatic thread-based subscriptions" auto- +matically subscribes the user in a discussion thread when they post in +a discussion, or start a new discussion - although the user can change +this. +

+ +

Finally, "Force thread-based subscriptions" also works in an automatic +manner, except that the user does not get the option to subscribe or +unsubscribe from the threads.

\ No newline at end of file Index: moodle/mod/forum/discuss.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/discuss.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 discuss.php --- moodle/mod/forum/discuss.php 20 Apr 2008 01:15:32 -0000 1.1.1.1 +++ moodle/mod/forum/discuss.php 30 Jan 2009 15:10:16 -0000 @@ -1,4 +1,4 @@ -id, 'id', $discussion->id); set_field('forum_read', 'forumid', $forumto->id, 'discussionid', $discussion->id); + $modcontextto = get_context_instance(CONTEXT_MODULE, $cmto->id); + forum_discussion_copy_subscribers($discussion->id, $forum->id, $discussion->id, $forumto->id, $modcontextto); add_to_log($course->id, 'forum', 'move discussion', "discuss.php?d=$discussion->id", $discussion->id, $cmto->id); require_once($CFG->libdir.'/rsslib.php'); @@ -156,8 +158,15 @@ /// Print the controls across the top - echo '
'; - + echo ''; + // Edit by JWC : add thread subscriptions + echo '\n"; } } - + // Edit by JWC : Add Subscribed yes/no button to thread summaries where needed + if ((has_capability('mod/forum:initialsubscriptions', $modcontext) || + has_capability('mod/forum:managesubscriptions', $modcontext)) && + forum_is_subscription_to_threads_allowed($USER->id, $forum)) { + echo ''; + } + // End of edit echo ''; + } + } echo ''; echo ''; @@ -4796,6 +5199,7 @@ } else { $group = -1; } + // Function edited by JWC for thread-based subscriptions forum_print_discussion_header($discussion, $forum, $group, $strdatestring, $cantrack, $forumtracked, $canviewparticipants, $context); break; Index: moodle/mod/forum/mod_form.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/mod_form.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 mod_form.php --- moodle/mod/forum/mod_form.php 27 Jul 2008 01:17:58 -0000 1.1.1.1 +++ moodle/mod/forum/mod_form.php 28 Jan 2009 12:38:03 -0000 @@ -1,4 +1,5 @@ -dirroot.'/course/moodleform_mod.php'); class mod_forum_mod_form extends moodleform_mod { @@ -34,9 +35,13 @@ $options = array(); $options[0] = get_string('no'); - $options[1] = get_string('yesforever', 'forum'); + $options[FORUM_FORCESUBSCRIBE] = get_string('yesforever', 'forum'); $options[FORUM_INITIALSUBSCRIBE] = get_string('yesinitially', 'forum'); $options[FORUM_DISALLOWSUBSCRIBE] = get_string('disallowsubscribe','forum'); + // Edit by JWC settings 4,5,6 + $options[FORUM_ALLOWTHREADSUBSCRIBE] = get_string('allowthreadsubs','forum'); + $options[FORUM_AUTOTHREADSUBSCRIBE] = get_string('autothreadsubs','forum'); + $options[FORUM_FORCETHREADSUBSCRIBE] = get_string('forcethreadsubs','forum'); $mform->addElement('select', 'forcesubscribe', get_string('forcesubscribeq', 'forum'), $options); $mform->setHelpButton('forcesubscribe', array('subscription2', get_string('forcesubscribeq', 'forum'), 'forum')); Index: moodle/mod/forum/post.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/post.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 post.php --- moodle/mod/forum/post.php 8 Oct 2008 01:20:48 -0000 1.1.1.1 +++ moodle/mod/forum/post.php 29 Jan 2009 18:43:44 -0000 @@ -1,4 +1,5 @@ -id, $newid); // update last post in each discussion - forum_discussion_update_last_post($discussion->id); + forum_discussion_update_last_post($discussion->forum, $discussion->id); forum_discussion_update_last_post($newid); + // Added by JWC : copy all subscriptions for old discussion over to new discussion + forum_discussion_copy_subscribers($discussion->id, $discussion->forum, $newid); add_to_log($discussion->course, "forum", "prune post", "discuss.php?d=$newid", "$post->id", $cm->id); @@ -500,8 +503,9 @@ $timemessage = 4; } $message .= '
'.get_string("postupdated", "forum"); - - if ($subscribemessage = forum_post_subscription($fromform, $forum)) { + + // Edit by JWC : added $realpost->discussion to parameters + if ($subscribemessage = forum_post_subscription($fromform, $forum, $realpost->discussion)) { $timemessage = 4; } if ($forum->type == 'single') { @@ -532,7 +536,8 @@ $timemessage = 4; } - if ($subscribemessage = forum_post_subscription($fromform, $forum)) { + // Edit by JWC : added $fromform->discussion to parameters + if ($subscribemessage = forum_post_subscription($fromform, $forum, $fromform->discussion)) { $timemessage = 4; } @@ -601,7 +606,8 @@ $message .= '

'.get_string("postaddedtimeleft", "forum", format_time($CFG->maxeditingtime)) . '

'; } - if ($subscribemessage = forum_post_subscription($discussion, $forum)) { + // Edit by JWC : added $discussion->id to parameters + if ($subscribemessage = forum_post_subscription($discussion, $forum, $discussion->id)) { $timemessage = 4; } @@ -729,23 +735,27 @@ } //load data into form - if (forum_is_subscribed($USER->id, $forum->id)) { $subscribe = true; - + // Added by JWC : Default state 1 + $opt = 1; } else if (forum_user_has_posted($forum->id, 0, $USER->id)) { $subscribe = false; - + // Added by JWC : Allow states 0, 2 or 3 based on settings + $opt = forum_is_subscription_to_threads_allowed($USER->id, $forum)?(($forum->forcesubscribe == FORUM_AUTOTHREADSUBSCRIBE || $forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE)?3:(!empty($USER->autosubscribe)?3:2)):0; } else { // user not posted yet - use subscription default specified in profile $subscribe = !empty($USER->autosubscribe); + // Added by JWC : Allow states 0, 1, 2, or 3 based on settings + $opt = forum_is_subscription_to_threads_allowed($USER->id, $forum)?(($forum->forcesubscribe == FORUM_AUTOTHREADSUBSCRIBE || $forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE)?3:$subscribe?3:2):($subscribe?1:0); } // HACK ALERT: this is very wrong, the defaults should be always initialized before calling $mform->get_data() !!! + // Edit by JWC : $opt replaces $subscribe?1:0 in array settings $mform_post->set_data(array( 'general'=>$heading, 'subject'=>$post->subject, 'message'=>$post->message, - 'subscribe'=>$subscribe?1:0, + 'subscribe'=>$opt, 'mailnow'=>!empty($post->mailnow), 'userid'=>$post->userid, 'parent'=>$post->parent, Index: moodle/mod/forum/post_form.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/post_form.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 post_form.php --- moodle/mod/forum/post_form.php 19 Jul 2008 01:17:50 -0000 1.1.1.1 +++ moodle/mod/forum/post_form.php 28 Jan 2009 16:40:56 -0000 @@ -1,4 +1,4 @@ -libdir.'/formslib.php'); @@ -6,7 +6,7 @@ function definition() { - global $CFG; + global $CFG, $USER; $mform =& $this->_form; $course = $this->_customdata['course']; @@ -41,12 +41,23 @@ $mform->addElement('hidden', 'subscribe'); $mform->setHelpButton('subscribemessage', array('subscription', get_string('subscription', 'forum'), 'forum')); + } else if ($forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE) { + + $mform->addElement('static', 'subscribemessage', get_string('subscription', 'forum'), get_string('forcesthreadsubs', 'forum')); + $mform->addElement('hidden', 'subscribe'); + $mform->setHelpButton('subscribemessage', array('subscription', get_string('subscription', 'forum'), 'forum')); + } else if (isset($forum->forcesubscribe)&& $forum->forcesubscribe != FORUM_DISALLOWSUBSCRIBE || has_capability('moodle/course:manageactivities', $coursecontext)) { $options = array(); - $options[0] = get_string('subscribestop', 'forum'); - $options[1] = get_string('subscribestart', 'forum'); + $options[FORUM_SUBSCRIBE_STOP] = get_string('subscribestop', 'forum'); + $options[FORUM_SUBSCRIBE_START] = get_string('subscribestart', 'forum'); + // Added by JWC : additional options for thread subscription + if (forum_is_subscription_to_threads_allowed($USER->id, $forum)) { + $options[FORUM_SUBSCRIBE_THREAD_STOP] = get_string('subscribestopthread', 'forum'); + $options[FORUM_SUBSCRIBE_THREAD_START] = get_string('subscribestartthread', 'forum'); + } $mform->addElement('select', 'subscribe', get_string('subscription', 'forum'), $options); $mform->setHelpButton('subscribe', array('subscription', get_string('subscription', 'forum'), 'forum')); Index: moodle/mod/forum/subscribe.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/subscribe.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 subscribe.php --- moodle/mod/forum/subscribe.php 14 Apr 2008 01:16:58 -0000 1.1.1.1 +++ moodle/mod/forum/subscribe.php 30 Jan 2009 15:26:06 -0000 @@ -1,4 +1,4 @@ -id : "view.php?f=$id"; + // Edit by JWC to add in 'autothread' if ($force and has_capability('mod/forum:managesubscriptions', $context)) { - if (forum_is_forcesubscribed($forum)) { - forum_forcesubscribe($forum->id, 0); - redirect($returnto, get_string("everyonecannowchoose", "forum"), 1); - } else { - forum_forcesubscribe($forum->id, 1); - redirect($returnto, get_string("everyoneisnowsubscribed", "forum"), 1); + switch($force) { + case 'no': + forum_forcesubscribe($forum->id, 0); + redirect($returnto, get_string("everyonecannowchoose", "forum"), 1); + break; + case 'yes': + forum_forcesubscribe($forum->id, FORUM_FORCESUBSCRIBE); + redirect($returnto, get_string("everyoneisnowsubscribed", "forum"), 1); + break; + case 'autothread': + forum_forcesubscribe($forum->id, FORUM_AUTOTHREADSUBSCRIBE); + redirect($returnto, get_string("autothreadsubscribed", "forum"), 1); } } + // Added by JWC for subscription by discussion thread + if ($thread and (has_capability('mod/forum:initialsubscriptions', $context) || + has_capability('mod/forum:managesubscriptions', $context))) { + // Use a 'soft' permission here to make sure the button/link works if it exists in the first place. + switch($subscribe) { + case 0: + forum_unsubscribe_thread($user->id, $forum->id, $thread); + redirect(($address=="discuss"?"discuss.php?d=".$thread:$returnto), get_string("unsubscribedthread", "forum"), 1); + break; + case 1: + forum_subscribe_thread($user->id, $forum->id, $thread); + redirect(($address=="discuss"?"discuss.php?d=".$thread:$returnto), get_string("subscribedthread", "forum"), 1); + } + } + if (forum_is_forcesubscribed($forum)) { redirect($returnto, get_string("everyoneisnowsubscribed", "forum"), 1); } Index: moodle/mod/forum/unsubscribeall.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/unsubscribeall.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 unsubscribeall.php --- moodle/mod/forum/unsubscribeall.php 7 Jul 2008 22:51:40 -0000 1.1.1.1 +++ moodle/mod/forum/unsubscribeall.php 29 Jan 2009 15:09:28 -0000 @@ -1,4 +1,4 @@ -libdir/rsslib.php"); @@ -119,11 +119,22 @@ if (forum_is_forcesubscribed($forum)) { $streveryoneisnowsubscribed = get_string('everyoneisnowsubscribed', 'forum'); $strallowchoice = get_string('allowchoice', 'forum'); + // Edit by JWC : addition of $strautothreadsubs + $strautothreadsubs = get_string('autothreadsubs', 'forum'); echo '' . get_string("forcessubscribe", 'forum') . '
'; helpbutton("subscription", $strallowchoice, "forum"); echo ' '; if (has_capability('mod/forum:managesubscriptions', $context)) { echo "id&force=no\">$strallowchoice"; + // Edit by JWC : Possible to turn on auto-thread subscriptions instead of just allowing forum subs. + if ($forum->forcesubscribe != FORUM_AUTOTHREADSUBSCRIBE) { + switch ($forum->type) { + case "single": + case "eachuser": break; + default: + echo "
id&force=autothread\">$strautothreadsubs"; + } + } } else { echo $streveryoneisnowsubscribed; } @@ -137,14 +148,40 @@ $streveryonecannowchoose = get_string("everyonecannowchoose", "forum"); $strforcesubscribe = get_string("forcesubscribe", "forum"); $strshowsubscribers = get_string("showsubscribers", "forum"); - echo '' . get_string("allowsallsubscribe", 'forum') . '
'; + // Edit by JWC : addition of $strautothreadsubs, $strautosubscriptions and $strforcesthreadsubs; use of $strthisforumsubs + $strautothreadsubs = get_string('autothreadsubs', 'forum'); + $strautosubscriptions = get_string('autosubscriptions', 'forum'); + $strallowsallsubs = get_string("allowsallsubscribe", 'forum'); + $strforcesthreadsubs = get_string("forcesthreadsubs", 'forum'); + switch($forum->forcesubscribe) { + case FORUM_AUTOTHREADSUBSCRIBE: + $strthisforumsubs = $strautosubscriptions; + break; + case FORUM_FORCETHREADSUBSCRIBE: + $strthisforumsubs = $strforcesthreadsubs; + break; + default: + $strthisforumsubs = $strallowsallsubs; + } + echo '' . $strthisforumsubs . '
'; helpbutton("subscription", $strforcesubscribe, "forum"); echo ' '; if (has_capability('mod/forum:managesubscriptions', $context)) { echo "id&force=yes\">$strforcesubscribe"; + // Edit by JWC : Possible to turn on auto-thread subscriptions instead of just forcing forum subs. + if ($forum->forcesubscribe != FORUM_AUTOTHREADSUBSCRIBE) { + switch ($forum->type) { + case "single": + case "eachuser": break; + default: + echo "
id&force=autothread\">$strautothreadsubs"; + } + } } else { - echo ''.$streveryonecannowchoose.''; + if ($forum->forcesubscribe != FORUM_FORCETHREADSUBSCRIBE) { + echo ''.$streveryonecannowchoose.''; + } } if(has_capability('mod/forum:viewsubscribers', $context)){
'; + if ((has_capability('mod/forum:initialsubscriptions', $modcontext) || + has_capability('mod/forum:managesubscriptions', $modcontext)) && + forum_is_subscription_to_threads_allowed($USER->id, $forum)) { + echo '
', forum_get_subscribe_thread_link($forum, $context, $discussion->id, FALSE, FALSE), '
'; + } + echo '
'; // groups selector not needed here echo ""; Index: moodle/mod/forum/lib.php =================================================================== RCS file: /Users/John/Documents/JWC/Moodle 1.9.3 CVS/moodle 1.9.3/moodle/mod/forum/lib.php,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 lib.php --- moodle/mod/forum/lib.php 8 Oct 2008 01:20:48 -0000 1.1.1.1 +++ moodle/mod/forum/lib.php 30 Jan 2009 15:25:54 -0000 @@ -1,5 +1,5 @@ -libdir.'/filelib.php'); /// CONSTANTS /////////////////////////////////////////////////////////// @@ -12,6 +12,18 @@ define('FORUM_FORCESUBSCRIBE', 1); define('FORUM_INITIALSUBSCRIBE', 2); define('FORUM_DISALLOWSUBSCRIBE',3); +// Added by JWC : settings 4,5,6 +define('FORUM_ALLOWTHREADSUBSCRIBE',4); +define('FORUM_AUTOTHREADSUBSCRIBE',5); +define('FORUM_FORCETHREADSUBSCRIBE',6); +/* Note: (Option 6) If users are pre-subscribed to forum, +their first post sets them to forced thread subscription */ + +// Added by JWC : settings 0 - 3 Form options +define ('FORUM_SUBSCRIBE_STOP', 0); +define ('FORUM_SUBSCRIBE_START', 1); +define ('FORUM_SUBSCRIBE_THREAD_STOP', 2); +define ('FORUM_SUBSCRIBE_THREAD_START', 3); define('FORUM_TRACKING_OFF', 0); define('FORUM_TRACKING_OPTIONAL', 1); @@ -224,7 +236,8 @@ $timenow = time(); $endtime = $timenow - $CFG->maxeditingtime; $starttime = $endtime - 48 * 3600; // Two days earlier - + + mtrace(' '); 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, @@ -278,8 +291,7 @@ continue; } } - - + // caching subscribed users of each forum if (!isset($subscribedusers[$forumid])) { if ($subusers = forum_subscribed_users($courses[$courseid], $forums[$forumid], 0, false)) { @@ -291,18 +303,47 @@ } continue; } - // this user is subscribed to this forum - $subscribedusers[$forumid][$postuser->id] = $postuser->id; + // Edit by JWC : now holds thread=0 for all threads + // this user is subscribed to this forum (or thread) + $subscribedusers[$forumid][$postuser->id][0] = $postuser->id; // this user is a user we have to process later $users[$postuser->id] = $postuser; + mtrace('user: '.$postuser->id.', forum: '.$forumid.', discussions: all'); } unset($subusers); // release memory } } - + // Added by JWC : now get user subscriptions to threads, add users if not already in $users array + // This must not be trapped within: if (!isset($subscribedusers[$forumid])), so if does not collect + // greedy user data except for users not already in $users array. + if (! forum_is_forcesubscribed($forum)) { + // Irrelevant if forum force-subscribed (Admin can't benefit here from thread subscription in forced forum!) + // Groups currently ignored here + // Any users in $users array cannot have emailstop set! + if ($subusersids = forum_subscribed_users_threads($forumid, $discussionid, 0)) { + foreach ($subusersids as $postuserid) { + if (!isset($users[$postuserid->id])) { + $postuser = forum_get_subscribed_user($postuserid->id); + if (isset($postuser[$postuserid->id])) { + $users[$postuserid->id] = $postuser[$postuserid->id]; + } + } + $subscribedusers[$forumid][$postuserid->id][$discussionid] = $postuserid->id; + mtrace('user: '.$postuserid->id.', forum: '.$forumid.', discussion: '.$discussionid.', post: '.$pid); + } + unset($subusersids); // release memory + } + } + + $mailcount[$pid] = 0; $errorcount[$pid] = 0; } + // Added by JWC : ksort will mean that mtrace will put entries into cron.php in userid order + // As the trace does not show the email addresses this seems more logical than ORDER BY u.email + // in forum_subscribed_users (some conditions). $sort parameter now removes sorting in the sql. + // Remove if speed is preferred over order in the cron. Email order immaterial! + ksort($users); } if ($users && $posts) { @@ -341,7 +382,8 @@ $cm =& $coursemodules[$forum->id]; // Do some checks to see if we can bail out now - if (!isset($subscribedusers[$forum->id][$userto->id])) { + // Edit by JWC : now checks thread id or thread=0 for all threads + if (!(isset($subscribedusers[$forum->id][$userto->id][0]) || isset($subscribedusers[$forum->id][$userto->id][$post->discussion]))) { continue; // user does not subscribe to this forum } @@ -357,7 +399,8 @@ // 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)) { + } else if ($userfrom = forum_get_subscribed_user($post->userid)) { + // JWC : small edit to collect selective records using forum_get_subscribed_user(), not all using get_record() $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); @@ -2462,7 +2505,7 @@ /** * Returns list of user objects that are subscribed to this forum */ -function forum_subscribed_users($course, $forum, $groupid=0) { +function forum_subscribed_users($course, $forum, $groupid=0, $sort=true) { global $CFG; @@ -2474,20 +2517,27 @@ $grouptables = ''; $groupselect = ''; } + + if ($sort) { + $sortorder = "u.email ASC"; + } else { + $sortorder = ""; + } if (forum_is_forcesubscribed($forum)) { $context = get_context_instance(CONTEXT_COURSE, $course->id); - $sort = "u.email ASC"; $fields ="u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat, u.maildigest, u.emailstop, u.imagealt, u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.timezone, u.theme, u.lang, u.trackforums, u.mnethostid"; - $results = get_users_by_capability($context, 'mod/forum:initialsubscriptions', $fields, $sort, '','','','', false, true); + $results = get_users_by_capability($context, 'mod/forum:initialsubscriptions', $fields, $sortorder, '','','','', false, true); } else { + // Edit by JWC : subcribers to threads removed by 'AND s.thread = 0' $results = get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat, u.maildigest, u.emailstop, u.imagealt, u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.timezone, u.theme, u.lang, u.trackforums, u.mnethostid FROM {$CFG->prefix}user u, {$CFG->prefix}forum_subscriptions s $grouptables WHERE s.forum = '$forum->id' AND s.userid = u.id + AND s.thread = 0 AND u.deleted = 0 $groupselect ORDER BY u.email ASC"); } @@ -2508,6 +2558,124 @@ return $results; } +/** + * Function added by JWC, as forum-user-thread would have multiple + * instances of user in a forum based heavily on forum_subscribed_users() + * Returns list of users who are subscribed by forum or thread + */ +function forum_subscribed_users_threads($forumid, $thread, $groupid=0) { + // Test for forum_is_forcesubscribed($forum) before entry + global $CFG; + + if ($groupid) { + $grouptables = ", {$CFG->prefix}groups_members gm "; + $groupselect = "AND gm.groupid = $groupid AND u.id = gm.userid"; + + } else { + $grouptables = ''; + $groupselect = ''; + } + + $sql = "SELECT u.id FROM {$CFG->prefix}user u, {$CFG->prefix}forum_subscriptions s $grouptables + WHERE s.forum = '{$forumid}' AND s.userid = u.id AND s.thread = '{$thread}' AND u.deleted = 0 $groupselect"; + //mtrace($sql); + $results = get_records_sql($sql); + + static $guestid = null; + + if (is_null($guestid)) { + if ($guest = guest_user()) { + $guestid = $guest->id; + } else { + $guestid = 0; + } + } + + // Guest user should never be subscribed to a forum. + unset($results[$guestid]); + + return $results; +} + +/** + * Function added by JWC, as to get information as forum_subscribed_users() + * but for a single user + * Returns list of users who are subscribed by forum or thread + */ +function forum_get_subscribed_user($userid) { + + global $CFG; + + $sql = "SELECT id, username, firstname, lastname, maildisplay, mailformat, maildigest, emailstop, imagealt, email, city, country, + lastaccess, lastlogin, picture, timezone, theme, lang, trackforums, mnethostid + FROM {$CFG->prefix}user WHERE id = '{$userid}' AND deleted = 0"; + $results = get_records_sql($sql); + + static $guestid = null; + + if (is_null($guestid)) { + if ($guest = guest_user()) { + $guestid = $guest->id; + } else { + $guestid = 0; + } + } + + // Guest user should never be subscribed to a forum. + unset($results[$guestid]); + + return $results; +} + +/** + * Function added by JWC, copy subscriptions for discussions from original + * thread to new discussion created by 'split' + */ +function forum_discussion_copy_subscribers($thread, $forumid, $newthread, $newforumid=NULL, $newcontext=NULL) { + // No need to check on subscriptions to new thread because there cannot be any + // Nor should there by subscriptions to whole forum as well as thread for 'split', + // but there may be for 'move' + global $CFG; + + $sql = "SELECT userid FROM {$CFG->prefix}forum_subscriptions + WHERE forum={$forumid} AND thread={$thread}"; + + if ($subscribers = get_records_sql($sql)) { + $data = new object(); + if (!isset($newforumid)) { + // Not a new forum so this is a 'split' + // Copy all exisint subscriptions from this thread to the new one + foreach ($subscribers as $subscriber) { + $data->userid = $subscriber->userid; + $data->forum = $forumid; + $data->thread = $newthread; + insert_record('forum_subscriptions', $data); + } + } else { + // This will be a new forum so this is a 'move' so + // remove all subscriptions to this thread in the donor forum. + forum_unsubscribe_all_from_thread($forumid, $thread); + // Check for whether thread subscriptions will be allowed in new forum, + // whether each user is allowed be subscribed there, (both initialsubscriptions + // and managesubscriptions have been used here to leave you only total non-subscribers), + // and whether the user is already subscribed to the forum as a whole. + if (forum_is_subscription_to_threads_allowed(0, $newforumid)) { + foreach ($subscribers as $subscriber) { + if (has_capability('mod/forum:initialsubscriptions', $newcontext, $subscriber->userid) || + has_capability('mod/forum:managesubscriptions', $newcontext, $subscriber->userid)) { + if (!forum_is_subscribed($subscriber->userid, $newforumid)) { + $data->userid = $subscriber->userid; + $data->forum = $newforumid; + $data->thread = $newthread; + insert_record('forum_subscriptions', $data); + } + } + } + } + } + } +} + // OTHER FUNCTIONS /////////////////////////////////////////////////////////// @@ -3149,7 +3317,15 @@ echo "'; + echo ''; + echo ''; $usedate = (empty($post->timemodified)) ? $post->modified : $post->timemodified; // Just in case $parenturl = (empty($post->lastpostid)) ? '' : '&parent='.$post->lastpostid; @@ -3928,10 +4104,16 @@ forum_tp_delete_read_records(-1, -1, $discussion->id); + // Added by JWC : delete discussion, so delete all user subscriptions to it + // largely redundant as these are removed in recursion of forum_delete_post() + if (! forum_unsubscribe_all_from_thread($forumid, $discussion->id)) { + $result = false; + } + if (! delete_records("forum_discussions", "id", "$discussion->id")) { $result = false; } - + return $result; } @@ -3949,6 +4131,10 @@ return false; } } + + // Added by JWC for thread-based suscriptions + forum_unsubscribe_user_from_thread($post); + if (delete_records("forum_posts", "id", $post->id)) { delete_records("forum_ratings", "post", $post->id); // Just in case @@ -3961,7 +4147,7 @@ forum_delete_old_attachments($post); } - // Just in case we are deleting the last post + // Just in case we are deleting the last post forum_discussion_update_last_post($post->discussion); return true; @@ -4018,15 +4204,54 @@ if (forum_is_forcesubscribed($forum)) { return true; } - return record_exists("forum_subscriptions", "userid", $userid, "forum", $forum->id); + // Edit by JWC : change record_exists call for one that tests for thread=0 + // so as not to confuse with thread subscriptions + $where = " userid='$userid' AND forum='$forum->id' AND thread=0"; + return record_exists_select("forum_subscriptions", $where); +} + +/** + * Function added by JWC : returns true if subscribed AT LEAST by thread + */ +function forum_is_subscribed_to_thread($userid, $forum, $threadid) { + if (is_numeric($forum)) { + $forum = get_record('forum', 'id', $forum); + } + if (forum_is_forcesubscribed($forum)) { + return true; + } + $where = " userid='$userid' AND forum='$forum->id' AND (thread='$threadid' OR thread=0)"; + return record_exists_select("forum_subscriptions", $where); +} + +/** + * Function added by JWC : returns true if subscribed by thread is allowed (by forum) + * and sensible (for user) + */ +function forum_is_subscription_to_threads_allowed($userid, $forum) { + if (is_numeric($forum)) { + $forum = get_record('forum', 'id', $forum); + } + switch ($forum->forcesubscribe) { + case FORUM_ALLOWTHREADSUBSCRIBE: + case FORUM_AUTOTHREADSUBSCRIBE: + case FORUM_FORCETHREADSUBSCRIBE: + return (empty($userid)?true:!forum_is_subscribed($userid, $forum)); + break; + default: + return false; + } + return true; } function forum_get_subscribed_forums($course) { + // Edited by JWC : addition of 'AND fs.thread=0' to leave out thread subscriptions global $USER, $CFG; $sql = "SELECT f.id FROM {$CFG->prefix}forum f LEFT JOIN {$CFG->prefix}forum_subscriptions fs ON (fs.forum = f.id AND fs.userid = $USER->id) WHERE f.forcesubscribe <> ".FORUM_DISALLOWSUBSCRIBE." + AND fs.thread=0 AND (f.forcesubscribe = ".FORUM_FORCESUBSCRIBE." OR fs.id IS NOT NULL)"; if ($subscribed = get_records_sql($sql)) { foreach ($subscribed as $s) { @@ -4042,15 +4267,15 @@ * Adds user to the subscriber list */ function forum_subscribe($userid, $forumid) { - - if (record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid)) { + if (record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid, "thread", "0")) { return true; } - + // Edit by JWC : remove thread-based subscriptions as redundant (note: no need for thread test here) + delete_records("forum_subscriptions", "userid", $userid, "forum", $forumid); + // End of JWC edit : note 'thread'=0 by default below $sub = new object(); $sub->userid = $userid; $sub->forum = $forumid; - return insert_record("forum_subscriptions", $sub); } @@ -4058,20 +4283,79 @@ * Removes user from the subscriber list */ function forum_unsubscribe($userid, $forumid) { + // Note by JWC: Unsubscribe from forum threaded or otherwise! No edit needed return delete_records("forum_subscriptions", "userid", $userid, "forum", $forumid); } /** + * Adds user subscription to forum thread + * Added by JWC for thread-based subscriptions + */ +function forum_subscribe_thread($userid, $forumid, $threadid) { + if (record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid, "thread", $threadid)) { + return true; + } + // Insert new record if record for this user/forum/thread doesn't exist + $sub = new object(); + $sub->userid = $userid; + $sub->forum = $forumid; + $sub->thread = $threadid; + return insert_record("forum_subscriptions", $sub); +} + +/** + * Removes user subscription to forum thread + * Added by JWC for thread-based subscriptions + */ +function forum_unsubscribe_thread($userid, $forumid, $threadid) { + // Remove only record for this user/forum/thread + $where = " userid='$userid' AND forum='$forumid' AND thread=$threadid"; + return delete_records_select("forum_subscriptions", $where); +} + +/** + * Removes all user subscriptions to forum thread + * Added by JWC for thread-based subscriptions + */ +function forum_unsubscribe_all_from_thread($forumid, $threadid) { + // Remove only records for all users in this thread + $where = " forum='$forumid' AND thread=$threadid"; + return delete_records_select("forum_subscriptions", $where); +} + +/** + * Removes user subscription to thread if only one post to thread is about to be deleted + * Added by JWC for thread-based subscriptions + */ +function forum_unsubscribe_user_from_thread($post) { + // Remove only record for this user/forum/thread + // Added by JWC : deletion of relevant thread subscription if only this post left, for this user, in this discussion + // $post must arrive with ->forum entry + global $CFG; + + $sql = "SELECT COUNT(*) FROM " . $CFG->prefix . "forum_posts WHERE discussion='{$post->discussion}' AND userid='{$post->userid}'"; + $count = count_records_sql($sql); + if ($count == 1) { + //$where = " id='{$post->discussion}'"; + //$discussion = get_record_select("forum_discussions", $where); + $where = " userid='{$post->userid}' AND forum='{$post->forum}' AND thread='{$post->discussion}'"; + return delete_records_select("forum_subscriptions", $where); + } +} + +/** * Given a new post, subscribes or unsubscribes as appropriate. * Returns some text which describes what happened. */ -function forum_post_subscription($post, $forum) { - +function forum_post_subscription($post, $forum, $threadid=0) { + // Edited by JWC for thread-based subscriptions global $USER; - $action = ''; $subscribed = forum_is_subscribed($USER->id, $forum); - + $info = new object(); + $info->name = fullname($USER); + $info->forum = format_string($forum->name); + if ($forum->forcesubscribe == FORUM_FORCESUBSCRIBE) { // database ignored return ""; @@ -4083,34 +4367,56 @@ return ""; } - } else { // go with the user's choice + } elseif ($forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE) { + forum_unsubscribe($USER->id, $forum->id); + $info->thread = $threadid; + forum_subscribe_thread($USER->id, $forum->id, $threadid); + return "

".get_string("nowsubscribed", "forum", $info)."

"; + + } else { // go with the user's choice, or pre-set to FORUM_SUBSCRIBE_THREAD_START if (isset($post->subscribe)) { - // no change - if ((!empty($post->subscribe) && $subscribed) - || (empty($post->subscribe) && !$subscribed)) { - return ""; - - } elseif (!empty($post->subscribe) && !$subscribed) { - $action = 'subscribe'; - - } elseif (empty($post->subscribe) && $subscribed) { - $action = 'unsubscribe'; + switch($post->subscribe) { + case FORUM_SUBSCRIBE_STOP: + // No change - do nothing + if (!$subscribed) return ""; + // else unsubscribe + forum_unsubscribe($USER->id, $forum->id); + return "

".get_string("nownotsubscribed", "forum", $info)."

"; + break; + + case FORUM_SUBSCRIBE_START: + // No change - do nothing + if ($subscribed) return ""; + // else subscribe + forum_subscribe($USER->id, $forum->id); + return "

".get_string("nowsubscribed", "forum", $info)."

"; + break; + + case FORUM_SUBSCRIBE_THREAD_STOP: + // If subscribed to forum, unsubscribing from thread is irrelevant! + if ($subscribed) return ""; + // else unsubscribe from thread + $info->thread = $threadid; + forum_unsubscribe_thread($USER->id, $forum->id, $threadid); + return "

".get_string("nownotsubscribed", "forum", $info)."

"; + break; + + case FORUM_SUBSCRIBE_THREAD_START: + // If subscribed to forum, subscribing from thread adds nothing! + // But if pre-subscribed to forum, and forum forces auto-thread + // subscription then there needs to be a get-out clause: + if ($forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE) { + forum_unsubscribe($USER->id, $forum->id); + $subscribed = false; + } + if ($subscribed) return ""; + // else subscribe to thread + $info->thread = $threadid; + forum_subscribe_thread($USER->id, $forum->id, $threadid); + return "

".get_string("nowsubscribed", "forum", $info)."

"; } } } - - $info = new object(); - $info->name = fullname($USER); - $info->forum = format_string($forum->name); - - switch ($action) { - case 'subscribe': - forum_subscribe($USER->id, $post->forum); - return "

".get_string("nowsubscribed", "forum", $info)."

"; - case 'unsubscribe': - forum_unsubscribe($USER->id, $post->forum); - return "

".get_string("nownotsubscribed", "forum", $info)."

"; - } } /** @@ -4138,6 +4444,8 @@ return $messages['forcesubscribed']; } else if ($forum->forcesubscribe == FORUM_DISALLOWSUBSCRIBE && !has_capability('mod/forum:managesubscriptions', $context)) { return $messages['cantsubscribe']; + } else if ($forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE && $fakelink) { + return ' '; } else if ($cantaccessagroup) { return $messages['cantaccessgroup']; } else { @@ -4187,6 +4495,93 @@ } } +/** + * Generate and return the subscribe or unsubscribe link for a forum. + * @param object $forum the forum. Fields used are $forum->id and $forum->forcesubscribe. + * @param object $context the context object for this forum. + * @param value $threadid the thread id in this forum. + * @param boolean $buttoned switches on/off button style link. + * @param boolean $backtoindex switches return action. + * + * Function added by JWC modelled on forum_get_subscribe_link() + * + */ +function forum_get_subscribe_thread_link($forum, $context, $threadid, $buttoned=true, $backtoindex=false) { + // Test validity of subscription linking BEFORE entering this function + global $CFG, $USER; + $messages = array( + 'button_yes' => get_string('yes'), + 'button_no' => get_string('no'), + 'subscribe' => get_string('subscribethisthread', 'forum'), + 'unsubscribe' => get_string('unsubscribethisthread', 'forum'), + 'start' => get_string('subscribestartthread', 'forum'), + 'stop' => get_string('subscribestopthread', 'forum'), + 'enforced' => get_string('forcesthreadsubs', 'forum'), + 'subscribed' => get_string('subscribedthread', 'forum'), + 'unsubscribed' => get_string('subscribedthreadno', 'forum') + ); + + $subscribed = forum_is_subscribed_to_thread($USER->id, $forum, $threadid); + $subscribe = !$subscribed; + + if ($forum->forcesubscribe == FORUM_FORCETHREADSUBSCRIBE) { + if ($buttoned) { + return($subscribed?$messages['button_yes']:$messages['button_no']); + } else { + return($messages['enforced']. '
'. ($subscribed?$messages['subscribed']:$messages['unsubscribed'])); + } + } + + if ($buttoned) { + if ($subscribed) { + $linktext = $messages['button_yes']; + $linktitle = $messages['stop']; + } else { + $linktext = $messages['button_no']; + $linktitle = $messages['start']; + } + } else { + if ($subscribed) { + $linktext = $messages['unsubscribe']; + $linktitle = $messages['stop']; + } else { + $linktext = $messages['subscribe']; + $linktitle = $messages['start']; + } + } + $options = array(); + if ($backtoindex) { + $backtoindexlink = '&backtoindex=1'; + $options['backtoindex'] = 1; + } else { + $backtoindexlink = ''; + } + $link = ''; + if (!$buttoned) { + $address = '&address=discuss'; + $link .= << +//wwwroot/mod/forum/subscribe.php?id={$forum->id}&thread={$threadid}&subscribe={$subscribe}{$address}{$backtoindexlink}'>$linktext<\/a>"; +} +//]]> + +'; + } + return $link; +} + /** * Generate and return the track or no track link for a forum. @@ -4748,6 +5143,14 @@ } echo ''; } + // Edit by JWC : table header for thread subscriptions + // Is there a more appropriate and complete permission to use? + if ((has_capability('mod/forum:initialsubscriptions', $context) || + has_capability('mod/forum:managesubscriptions', $context)) && + forum_is_subscription_to_threads_allowed($USER->id, $forum)) { + echo '
'.get_string('subscribedthreadq', 'forum').''.get_string('lastpost', 'forum').'