MDL-22783 upgrade enrol/flatfile plugin to use enrolments
[moodle.git] / mod / forum / lib.php
CommitLineData
df1ba0f4 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
8f685009 19 * @package mod-forum
df1ba0f4 20 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 */
23
24/** Include required files */
f1e0649c 25require_once($CFG->libdir.'/filelib.php');
3b120e46 26require_once($CFG->libdir.'/eventslib.php');
4e1132a8 27require_once($CFG->libdir . '/completionlib.php');
c23c9009 28require_once($CFG->dirroot.'/user/selector/lib.php');
7f6689e4 29
501cdbd8 30/// CONSTANTS ///////////////////////////////////////////////////////////
f93f848a 31
d3583b41 32define('FORUM_MODE_FLATOLDEST', 1);
33define('FORUM_MODE_FLATNEWEST', -1);
34define('FORUM_MODE_THREADED', 2);
35define('FORUM_MODE_NESTED', 3);
2e2e71a8 36
afef965e 37define('FORUM_CHOOSESUBSCRIBE', 0);
d3583b41 38define('FORUM_FORCESUBSCRIBE', 1);
39define('FORUM_INITIALSUBSCRIBE', 2);
098d27d4 40define('FORUM_DISALLOWSUBSCRIBE',3);
709f0ec8 41
eaf50aef 42define('FORUM_TRACKING_OFF', 0);
43define('FORUM_TRACKING_OPTIONAL', 1);
44define('FORUM_TRACKING_ON', 2);
45
caadf009 46/// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
47
0a4ac01b 48/**
49 * Given an object containing all the necessary data,
7cac0c4b 50 * (defined by the form in mod_form.php) this function
0a4ac01b 51 * will create a new instance and return the id number
52 * of the new instance.
df1ba0f4 53 *
54 * @global object
55 * @global object
90f4745c 56 * @param object $forum add forum instance (with magic quotes)
6b7de0bb 57 * @return int intance id
3a5e1d06 58 */
caadf009 59function forum_add_instance($forum) {
c18269c7 60 global $CFG, $DB;
caadf009 61
62 $forum->timemodified = time();
63
353228d8 64 if (empty($forum->assessed)) {
f2f56406 65 $forum->assessed = 0;
66 }
2b63df96 67
353228d8 68 if (empty($forum->ratingtime) or empty($forum->assessed)) {
98914efd 69 $forum->assesstimestart = 0;
70 $forum->assesstimefinish = 0;
71 }
caadf009 72
a8f3a651 73 $forum->id = $DB->insert_record('forum', $forum);
cb9a975f 74
d3583b41 75 if ($forum->type == 'single') { // Create related discussion.
353228d8 76 $discussion = new object();
e2d7687f 77 $discussion->course = $forum->course;
78 $discussion->forum = $forum->id;
79 $discussion->name = $forum->name;
e2d7687f 80 $discussion->assessed = $forum->assessed;
6606c00f
MD
81 $discussion->message = $forum->intro;
82 $discussion->messageformat = $forum->introformat;
83 $discussion->messagetrust = trusttext_trusted(get_context_instance(CONTEXT_COURSE, $forum->course));
e2d7687f 84 $discussion->mailnow = false;
85 $discussion->groupid = -1;
caadf009 86
dbf4d660 87 $message = '';
88
89 if (! forum_add_discussion($discussion, null, $message)) {
12e57b92 90 print_error('cannotadd', 'forum');
caadf009 91 }
92 }
8f0cd6ef 93
3c268f25 94 if ($forum->forcesubscribe == FORUM_INITIALSUBSCRIBE) {
8d8d0bfa 95 /// all users should be subscribed initially
96 /// Note: forum_get_potential_subscribers should take the forum context,
97 /// but that does not exist yet, becuase the forum is only half build at this
98 /// stage. However, because the forum is brand new, we know that there are
99 /// no role assignments or overrides in the forum context, so using the
100 /// course context gives the same list of users.
081cce73 101 $users = forum_get_potential_subscribers(get_context_instance(CONTEXT_COURSE, $forum->course), 0, 'u.id, u.email', '');
709f0ec8 102 foreach ($users as $user) {
103 forum_subscribe($user->id, $forum->id);
104 }
105 }
caadf009 106
612607bd 107 forum_grade_item_update($forum);
353228d8 108
caadf009 109 return $forum->id;
110}
111
112
13bbe067 113/**
0a4ac01b 114 * Given an object containing all the necessary data,
7cac0c4b 115 * (defined by the form in mod_form.php) this function
0a4ac01b 116 * will update an existing instance with new data.
df1ba0f4 117 *
118 * @global object
90f4745c 119 * @param object $forum forum instance (with magic quotes)
6b7de0bb 120 * @return bool success
90f4745c 121 */
caadf009 122function forum_update_instance($forum) {
862f5a49 123 global $DB, $OUTPUT, $USER;
c18269c7 124
caadf009 125 $forum->timemodified = time();
353228d8 126 $forum->id = $forum->instance;
caadf009 127
f0da6b85 128 if (empty($forum->assessed)) {
f2f56406 129 $forum->assessed = 0;
130 }
2b63df96 131
353228d8 132 if (empty($forum->ratingtime) or empty($forum->assessed)) {
98914efd 133 $forum->assesstimestart = 0;
134 $forum->assesstimefinish = 0;
135 }
136
c18269c7 137 $oldforum = $DB->get_record('forum', array('id'=>$forum->id));
13bbe067 138
139 // MDL-3942 - if the aggregation type or scale (i.e. max grade) changes then recalculate the grades for the entire forum
140 // if scale changes - do we need to recheck the ratings, if ratings higher than scale how do we want to respond?
141 // 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
142 if (($oldforum->assessed<>$forum->assessed) or ($oldforum->scale<>$forum->scale)) {
143 forum_update_grades($forum); // recalculate grades for the forum
144 }
145
d3583b41 146 if ($forum->type == 'single') { // Update related discussion and post.
c18269c7 147 if (! $discussion = $DB->get_record('forum_discussions', array('forum'=>$forum->id))) {
148 if ($discussions = $DB->get_records('forum_discussions', array('forum'=>$forum->id), 'timemodified ASC')) {
9146b979 149 echo $OUTPUT->notification('Warning! There is more than one discussion in this forum - using the most recent');
caadf009 150 $discussion = array_pop($discussions);
151 } else {
66482658 152 // try to recover by creating initial discussion - MDL-16262
153 $discussion = new object();
e2d7687f 154 $discussion->course = $forum->course;
155 $discussion->forum = $forum->id;
156 $discussion->name = $forum->name;
e2d7687f 157 $discussion->assessed = $forum->assessed;
6606c00f
MD
158 $discussion->message = $forum->intro;
159 $discussion->messageformat = $forum->introformat;
160 $discussion->messagetrust = true;
e2d7687f 161 $discussion->mailnow = false;
162 $discussion->groupid = -1;
66482658 163
164 forum_add_discussion($discussion, null, $message);
165
166 if (! $discussion = $DB->get_record('forum_discussions', array('forum'=>$forum->id))) {
167 print_error('cannotadd', 'forum');
168 }
caadf009 169 }
170 }
c18269c7 171 if (! $post = $DB->get_record('forum_posts', array('id'=>$discussion->firstpost))) {
12e57b92 172 print_error('cannotfindfirstpost', 'forum');
caadf009 173 }
174
6606c00f
MD
175 $cm = get_coursemodule_from_instance('forum', $forum->id);
176 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
177
178 $post->subject = $forum->name;
179 $post->message = $forum->intro;
180 $post->messageformat = $forum->introformat;
181 $post->messagetrust = trusttext_trusted($modcontext);
182 $post->modified = $forum->timemodified;
183 $post->userid = $USER->id; // MDL-18599, so that current teacher can take ownership of activities
caadf009 184
a8d6ef8c 185 $DB->update_record('forum_posts', $post);
caadf009 186 $discussion->name = $forum->name;
a8d6ef8c 187 $DB->update_record('forum_discussions', $discussion);
caadf009 188 }
189
a8d6ef8c 190 $DB->update_record('forum', $forum);
353228d8 191
353228d8 192 forum_grade_item_update($forum);
193
194 return true;
caadf009 195}
196
197
0a4ac01b 198/**
199 * Given an ID of an instance of this module,
200 * this function will permanently delete the instance
201 * and any data that depends on it.
df1ba0f4 202 *
203 * @global object
204 * @param int $id forum instance id
90f4745c 205 * @return bool success
0a4ac01b 206 */
caadf009 207function forum_delete_instance($id) {
c18269c7 208 global $DB;
caadf009 209
c18269c7 210 if (!$forum = $DB->get_record('forum', array('id'=>$id))) {
caadf009 211 return false;
212 }
455a8fed 213 if (!$cm = get_coursemodule_from_instance('forum', $forum->id)) {
214 return false;
215 }
216 if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
217 return false;
218 }
219
220 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
caadf009 221
fa686bc4 222 // now get rid of all files
223 $fs = get_file_storage();
455a8fed 224 $fs->delete_area_files($context->id);
fa686bc4 225
caadf009 226 $result = true;
227
c18269c7 228 if ($discussions = $DB->get_records('forum_discussions', array('forum'=>$forum->id))) {
caadf009 229 foreach ($discussions as $discussion) {
455a8fed 230 if (!forum_delete_discussion($discussion, true, $course, $cm, $forum)) {
caadf009 231 $result = false;
232 }
233 }
234 }
235
c18269c7 236 if (!$DB->delete_records('forum_subscriptions', array('forum'=>$forum->id))) {
caadf009 237 $result = false;
238 }
239
f37da850 240 forum_tp_delete_read_records(-1, -1, -1, $forum->id);
241
415f8c3e 242 if (!$DB->delete_records('forum', array('id'=>$forum->id))) {
caadf009 243 $result = false;
244 }
245
353228d8 246 forum_grade_item_delete($forum);
247
caadf009 248 return $result;
249}
250
251
4e781c7b 252/**
253 * Indicates API features that the forum supports.
254 *
df1ba0f4 255 * @uses FEATURE_GROUPS
256 * @uses FEATURE_GROUPINGS
257 * @uses FEATURE_GROUPMEMBERSONLY
258 * @uses FEATURE_MOD_INTRO
259 * @uses FEATURE_COMPLETION_TRACKS_VIEWS
260 * @uses FEATURE_COMPLETION_HAS_RULES
261 * @uses FEATURE_GRADE_HAS_GRADE
262 * @uses FEATURE_GRADE_OUTCOMES
4e781c7b 263 * @param string $feature
264 * @return mixed True if yes (some features may use other values)
265 */
266function forum_supports($feature) {
267 switch($feature) {
42f103be 268 case FEATURE_GROUPS: return true;
269 case FEATURE_GROUPINGS: return true;
270 case FEATURE_GROUPMEMBERSONLY: return true;
dc5c2bd9 271 case FEATURE_MOD_INTRO: return true;
4e781c7b 272 case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
42f103be 273 case FEATURE_COMPLETION_HAS_RULES: return true;
274 case FEATURE_GRADE_HAS_GRADE: return true;
275 case FEATURE_GRADE_OUTCOMES: return true;
4bfdcfcf
EL
276 case FEATURE_RATE: return true;
277 case FEATURE_BACKUP_MOODLE2: return true;
42f103be 278
49f6e5f4 279 default: return null;
4e781c7b 280 }
281}
282
283
284/**
285 * Obtains the automatic completion state for this forum based on any conditions
286 * in forum settings.
287 *
df1ba0f4 288 * @global object
289 * @global object
4e781c7b 290 * @param object $course Course
291 * @param object $cm Course-module
292 * @param int $userid User ID
293 * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
294 * @return bool True if completed, false if not. (If no conditions, then return
295 * value depends on comparison type)
296 */
297function forum_get_completion_state($course,$cm,$userid,$type) {
298 global $CFG,$DB;
299
300 // Get forum details
6093af9b 301 if (!($forum=$DB->get_record('forum',array('id'=>$cm->instance)))) {
4e781c7b 302 throw new Exception("Can't find forum {$cm->instance}");
303 }
304
305 $result=$type; // Default return value
306
307 $postcountparams=array('userid'=>$userid,'forumid'=>$forum->id);
308 $postcountsql="
5e7f2b0b 309SELECT
310 COUNT(1)
311FROM
312 {forum_posts} fp
49f6e5f4 313 INNER JOIN {forum_discussions} fd ON fp.discussion=fd.id
4e781c7b 314WHERE
315 fp.userid=:userid AND fd.forum=:forumid";
316
6093af9b 317 if ($forum->completiondiscussions) {
4e781c7b 318 $value = $forum->completiondiscussions <=
6093af9b 319 $DB->count_records('forum_discussions',array('forum'=>$forum->id,'userid'=>$userid));
320 if ($type == COMPLETION_AND) {
321 $result = $result && $value;
4e781c7b 322 } else {
6093af9b 323 $result = $result || $value;
4e781c7b 324 }
325 }
6093af9b 326 if ($forum->completionreplies) {
5e7f2b0b 327 $value = $forum->completionreplies <=
6093af9b 328 $DB->get_field_sql( $postcountsql.' AND fp.parent<>0',$postcountparams);
329 if ($type==COMPLETION_AND) {
330 $result = $result && $value;
4e781c7b 331 } else {
6093af9b 332 $result = $result || $value;
4e781c7b 333 }
334 }
6093af9b 335 if ($forum->completionposts) {
4e781c7b 336 $value = $forum->completionposts <= $DB->get_field_sql($postcountsql,$postcountparams);
6093af9b 337 if ($type == COMPLETION_AND) {
338 $result = $result && $value;
4e781c7b 339 } else {
6093af9b 340 $result = $result || $value;
4e781c7b 341 }
342 }
343
5e7f2b0b 344 return $result;
4e781c7b 345}
346
347
0a4ac01b 348/**
349 * Function to be run periodically according to the moodle cron
350 * Finds all posts that have yet to be mailed out, and mails them
351 * out to all subscribers
df1ba0f4 352 *
353 * @global object
354 * @global object
355 * @global object
356 * @uses CONTEXT_MODULE
357 * @uses CONTEXT_COURSE
358 * @uses SITEID
359 * @uses FORMAT_PLAIN
90f4745c 360 * @return void
361 */
0fa18d5a 362function forum_cron() {
4e445355 363 global $CFG, $USER, $DB;
857b798b 364
a974c799 365 $site = get_site();
366
367 // all users that are subscribed to any post that needs sending
368 $users = array();
369
370 // status arrays
371 $mailcount = array();
372 $errorcount = array();
373
374 // caches
375 $discussions = array();
376 $forums = array();
377 $courses = array();
378 $coursemodules = array();
a974c799 379 $subscribedusers = array();
aaf7a9dc 380
ec2137ba 381
0a4ac01b 382 // Posts older than 2 days will not be mailed. This is to avoid the problem where
383 // cron has not been running for a long time, and then suddenly people are flooded
384 // with mail from the past few weeks or months
3ecca1ee 385 $timenow = time();
386 $endtime = $timenow - $CFG->maxeditingtime;
0a4ac01b 387 $starttime = $endtime - 48 * 3600; // Two days earlier
3ecca1ee 388
90f4745c 389 if ($posts = forum_get_unmailed_posts($starttime, $endtime, $timenow)) {
0a4ac01b 390 // Mark them all now as being mailed. It's unlikely but possible there
391 // might be an error later so that a post is NOT actually mailed out,
392 // but since mail isn't crucial, we can accept this risk. Doing it now
393 // prevents the risk of duplicated mails, which is a worse problem.
16b4e5b6 394
5fac3a5e 395 if (!forum_mark_old_posts_as_mailed($endtime)) {
396 mtrace('Errors occurred while trying to mark some posts as being mailed.');
397 return false; // Don't continue trying to mail them, in case we are in a cron loop
398 }
399
400 // checking post validity, and adding users to loop through later
401 foreach ($posts as $pid => $post) {
402
a974c799 403 $discussionid = $post->discussion;
404 if (!isset($discussions[$discussionid])) {
4e445355 405 if ($discussion = $DB->get_record('forum_discussions', array('id'=> $post->discussion))) {
a974c799 406 $discussions[$discussionid] = $discussion;
407 } else {
408 mtrace('Could not find discussion '.$discussionid);
409 unset($posts[$pid]);
410 continue;
411 }
5fac3a5e 412 }
a974c799 413 $forumid = $discussions[$discussionid]->forum;
414 if (!isset($forums[$forumid])) {
4e445355 415 if ($forum = $DB->get_record('forum', array('id' => $forumid))) {
a974c799 416 $forums[$forumid] = $forum;
417 } else {
418 mtrace('Could not find forum '.$forumid);
419 unset($posts[$pid]);
420 continue;
421 }
5fac3a5e 422 }
a974c799 423 $courseid = $forums[$forumid]->course;
424 if (!isset($courses[$courseid])) {
4e445355 425 if ($course = $DB->get_record('course', array('id' => $courseid))) {
a974c799 426 $courses[$courseid] = $course;
427 } else {
428 mtrace('Could not find course '.$courseid);
429 unset($posts[$pid]);
430 continue;
431 }
5fac3a5e 432 }
a974c799 433 if (!isset($coursemodules[$forumid])) {
434 if ($cm = get_coursemodule_from_instance('forum', $forumid, $courseid)) {
435 $coursemodules[$forumid] = $cm;
436 } else {
437 mtrace('Could not course module for forum '.$forumid);
438 unset($posts[$pid]);
439 continue;
440 }
441 }
442
443
5fac3a5e 444 // caching subscribed users of each forum
a974c799 445 if (!isset($subscribedusers[$forumid])) {
48dcaf58 446 $modcontext = get_context_instance(CONTEXT_MODULE, $coursemodules[$forumid]->id);
447 if ($subusers = forum_subscribed_users($courses[$courseid], $forums[$forumid], 0, $modcontext)) {
704ca25c 448 foreach ($subusers as $postuser) {
a974c799 449 // do not try to mail users with stopped email
450 if ($postuser->emailstop) {
f4528bdc 451 if (!empty($CFG->forum_logblocked)) {
452 add_to_log(SITEID, 'forum', 'mail blocked', '', '', 0, $postuser->id);
453 }
a974c799 454 continue;
455 }
704ca25c 456 // this user is subscribed to this forum
a5cef9c8 457 $subscribedusers[$forumid][$postuser->id] = $postuser->id;
704ca25c 458 // this user is a user we have to process later
a974c799 459 $users[$postuser->id] = $postuser;
704ca25c 460 }
a5cef9c8 461 unset($subusers); // release memory
a974c799 462 }
5fac3a5e 463 }
a974c799 464
5fac3a5e 465 $mailcount[$pid] = 0;
466 $errorcount[$pid] = 0;
a974c799 467 }
5fac3a5e 468 }
caadf009 469
4dad2828 470 if ($users && $posts) {
edffca15 471
857b798b 472 $urlinfo = parse_url($CFG->wwwroot);
473 $hostname = $urlinfo['host'];
474
5fac3a5e 475 foreach ($users as $userto) {
a974c799 476
477 @set_time_limit(120); // terminate if processing of any account takes longer than 2 minutes
478
4dad2828 479 // set this so that the capabilities are cached, and environment matches receiving user
e8b7114d 480 cron_setup_user($userto);
a974c799 481
16b4e5b6 482 mtrace('Processing user '.$userto->id);
caadf009 483
df1c2c71 484 // init caches
485 $userto->viewfullnames = array();
486 $userto->canpost = array();
90f4745c 487 $userto->markposts = array();
488 $userto->enrolledin = array();
669f2499 489
9db5d080 490 // reset the caches
491 foreach ($coursemodules as $forumid=>$unused) {
492 $coursemodules[$forumid]->cache = new object();
493 $coursemodules[$forumid]->cache->caps = array();
494 unset($coursemodules[$forumid]->uservisible);
495 }
496
4dad2828 497 foreach ($posts as $pid => $post) {
caadf009 498
4dad2828 499 // Set up the environment for the post, discussion, forum, course
a974c799 500 $discussion = $discussions[$post->discussion];
501 $forum = $forums[$discussion->forum];
502 $course = $courses[$forum->course];
90f4745c 503 $cm =& $coursemodules[$forum->id];
4dad2828 504
505 // Do some checks to see if we can bail out now
a5cef9c8 506 if (!isset($subscribedusers[$forum->id][$userto->id])) {
a974c799 507 continue; // user does not subscribe to this forum
4dad2828 508 }
4dad2828 509
90f4745c 510 // Verify user is enrollend in course - if not do not send any email
511 if (!isset($userto->enrolledin[$course->id])) {
4f0c2d00 512 $userto->enrolledin[$course->id] = is_enrolled(get_context_instance(CONTEXT_COURSE, $course->id));
90f4745c 513 }
514 if (!$userto->enrolledin[$course->id]) {
515 // oops - this user should not receive anything from this course
516 continue;
517 }
518
a5cef9c8 519 // Get info about the sending user
520 if (array_key_exists($post->userid, $users)) { // we might know him/her already
521 $userfrom = $users[$post->userid];
4e445355 522 } else if ($userfrom = $DB->get_record('user', array('id' => $post->userid))) {
a5cef9c8 523 $users[$userfrom->id] = $userfrom; // fetch only once, we can add it to user list, it will be skipped anyway
524 } else {
525 mtrace('Could not find user '.$post->userid);
526 continue;
527 }
528
505ab5aa
AD
529 //if we want to check that userto and userfrom are not the same person this is probably the spot to do it
530
a974c799 531 // setup global $COURSE properly - needed for roles and languages
e8b7114d 532 cron_setup_user($userto, $course);
4dad2828 533
df1c2c71 534 // Fill caches
535 if (!isset($userto->viewfullnames[$forum->id])) {
536 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
537 $userto->viewfullnames[$forum->id] = has_capability('moodle/site:viewfullnames', $modcontext);
538 }
8b79a625 539 if (!isset($userto->canpost[$discussion->id])) {
df1c2c71 540 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
8b79a625 541 $userto->canpost[$discussion->id] = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
df1c2c71 542 }
543 if (!isset($userfrom->groups[$forum->id])) {
544 if (!isset($userfrom->groups)) {
545 $userfrom->groups = array();
546 $users[$userfrom->id]->groups = array();
547 }
548 $userfrom->groups[$forum->id] = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
549 $users[$userfrom->id]->groups[$forum->id] = $userfrom->groups[$forum->id];
550 }
9f2ded76 551
a974c799 552 // Make sure groups allow this user to see this email
df1c2c71 553 if ($discussion->groupid > 0 and $groupmode = groups_get_activity_groupmode($cm, $course)) { // Groups are being used
9f2ded76 554 if (!groups_group_exists($discussion->groupid)) { // Can't find group
38bd362a 555 continue; // Be safe and don't send it to anyone
5fac3a5e 556 }
918e9805 557
2c386f82 558 if (!groups_is_member($discussion->groupid) and !has_capability('moodle/site:accessallgroups', $modcontext)) {
38bd362a 559 // do not send posts from other groups when in SEPARATEGROUPS or VISIBLEGROUPS
560 continue;
9197e147 561 }
4dad2828 562 }
2b63df96 563
4dad2828 564 // Make sure we're allowed to see it...
9f2ded76 565 if (!forum_user_can_see_post($forum, $discussion, $post, NULL, $cm)) {
4dad2828 566 mtrace('user '.$userto->id. ' can not see '.$post->id);
567 continue;
568 }
569
570 // OK so we need to send the email.
571
572 // Does the user want this post in a digest? If so postpone it for now.
573 if ($userto->maildigest > 0) {
574 // This user wants the mails to be in digest form
a974c799 575 $queue = new object();
576 $queue->userid = $userto->id;
4dad2828 577 $queue->discussionid = $discussion->id;
a974c799 578 $queue->postid = $post->id;
90f4745c 579 $queue->timemodified = $post->created;
fc29e51b 580 $DB->insert_record('forum_queue', $queue);
4dad2828 581 continue;
582 }
65b0e537 583
4dad2828 584
585 // Prepare to actually send the post now, and build up the content
586
a974c799 587 $cleanforumname = str_replace('"', "'", strip_tags(format_string($forum->name)));
4dad2828 588
589 $userfrom->customheaders = array ( // Headers to make emails easier to track
590 'Precedence: Bulk',
591 'List-Id: "'.$cleanforumname.'" <moodleforum'.$forum->id.'@'.$hostname.'>',
592 'List-Help: '.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id,
593 'Message-ID: <moodlepost'.$post->id.'@'.$hostname.'>',
594 'In-Reply-To: <moodlepost'.$post->parent.'@'.$hostname.'>',
595 'References: <moodlepost'.$post->parent.'@'.$hostname.'>',
596 'X-Course-Id: '.$course->id,
a974c799 597 'X-Course-Name: '.format_string($course->fullname, true)
4dad2828 598 );
a974c799 599
4dad2828 600
601 $postsubject = "$course->shortname: ".format_string($post->subject,true);
0faf6791 602 $posttext = forum_make_mail_text($course, $cm, $forum, $discussion, $post, $userfrom, $userto);
603 $posthtml = forum_make_mail_html($course, $cm, $forum, $discussion, $post, $userfrom, $userto);
4dad2828 604
605 // Send the post now!
606
607 mtrace('Sending ', '');
5e7f2b0b 608
3b120e46 609 $eventdata = new object();
505ab5aa 610 $eventdata->component = 'mod_forum';
120b3758 611 $eventdata->name = 'posts';
3b120e46 612 $eventdata->userfrom = $userfrom;
613 $eventdata->userto = $userto;
614 $eventdata->subject = $postsubject;
615 $eventdata->fullmessage = $posttext;
616 $eventdata->fullmessageformat = FORMAT_PLAIN;
617 $eventdata->fullmessagehtml = $posthtml;
618 $eventdata->smallmessage = '';
3b120e46 619
505ab5aa
AD
620 $mailresult = message_send($eventdata);
621 if (!$mailresult){
622 mtrace("Error: mod/forum/lib.php forum_cron(): Could not send out mail for id $post->id to user $userto->id".
4dad2828 623 " ($userto->email) .. not trying again.");
624 add_to_log($course->id, 'forum', 'mail error', "discuss.php?d=$discussion->id#p$post->id",
625 substr(format_string($post->subject,true),0,30), $cm->id, $userto->id);
626 $errorcount[$post->id]++;
627 } else if ($mailresult === 'emailstop') {
a974c799 628 // should not be reached anymore - see check above
505ab5aa 629 mtrace("Error: mod/forum/lib.php forum_cron(): received 'emailstop' while sending out mail for id $post->id to user $userto->id ($userto->email)");
4dad2828 630 } else {
631 $mailcount[$post->id]++;
632
0a4ac01b 633 // Mark post as read if forum_usermarksread is set off
90f4745c 634 if (!$CFG->forum_usermarksread) {
635 $userto->markposts[$post->id] = $post->id;
caadf009 636 }
aaf7a9dc 637 }
4dad2828 638
639 mtrace('post '.$post->id. ': '.$post->subject);
aaf7a9dc 640 }
90f4745c 641
642 // mark processed posts as read
643 forum_tp_mark_posts_read($userto, $userto->markposts);
5fac3a5e 644 }
645 }
646
647 if ($posts) {
648 foreach ($posts as $post) {
16b4e5b6 649 mtrace($mailcount[$post->id]." users were sent post $post->id, '$post->subject'");
5fac3a5e 650 if ($errorcount[$post->id]) {
4e445355 651 $DB->set_field("forum_posts", "mailed", "2", array("id" => "$post->id"));
a974c799 652 }
aaf7a9dc 653 }
654 }
655
8cb121cc 656 // release some memory
657 unset($subscribedusers);
658 unset($mailcount);
659 unset($errorcount);
660
e8b7114d 661 cron_setup_user();
ad9ff3d3 662
9152fc99 663 $sitetimezone = $CFG->timezone;
944a2b28 664
0a4ac01b 665 // Now see if there are any digest mails waiting to be sent, and if we should send them
aaf7a9dc 666
f3c3a4d3 667 mtrace('Starting digest processing...');
668
910b6fa7 669 @set_time_limit(300); // terminate if not able to fetch all digests in 5 minutes
670
8f0cd6ef 671 if (!isset($CFG->digestmailtimelast)) { // To catch the first time
ca8e8a10 672 set_config('digestmailtimelast', 0);
673 }
674
675 $timenow = time();
944a2b28 676 $digesttime = usergetmidnight($timenow, $sitetimezone) + ($CFG->digestmailtime * 3600);
ca8e8a10 677
f3c3a4d3 678 // Delete any really old ones (normally there shouldn't be any)
679 $weekago = $timenow - (7 * 24 * 3600);
2ac897cd 680 $DB->delete_records_select('forum_queue', "timemodified < ?", array($weekago));
910b6fa7 681 mtrace ('Cleaned old digest records');
9f2ded76 682
ca8e8a10 683 if ($CFG->digestmailtimelast < $digesttime and $timenow > $digesttime) {
b140ae85 684
b140ae85 685 mtrace('Sending forum digests: '.userdate($timenow, '', $sitetimezone));
686
4e445355 687 $digestposts_rs = $DB->get_recordset_select('forum_queue', "timemodified < ?", array($digesttime));
910b6fa7 688
4e445355 689 if ($digestposts_rs->valid()) {
8ad64455 690
aaf7a9dc 691 // We have work to do
692 $usermailcount = 0;
aaf7a9dc 693
a974c799 694 //caches - reuse the those filled before too
aaf7a9dc 695 $discussionposts = array();
696 $userdiscussions = array();
a974c799 697
4e445355 698 foreach ($digestposts_rs as $digestpost) {
a974c799 699 if (!isset($users[$digestpost->userid])) {
4e445355 700 if ($user = $DB->get_record('user', array('id' => $digestpost->userid))) {
a974c799 701 $users[$digestpost->userid] = $user;
702 } else {
703 continue;
704 }
705 }
706 $postuser = $users[$digestpost->userid];
707 if ($postuser->emailstop) {
f4528bdc 708 if (!empty($CFG->forum_logblocked)) {
709 add_to_log(SITEID, 'forum', 'mail blocked', '', '', 0, $postuser->id);
710 }
a974c799 711 continue;
712 }
713
714 if (!isset($posts[$digestpost->postid])) {
4e445355 715 if ($post = $DB->get_record('forum_posts', array('id' => $digestpost->postid))) {
a974c799 716 $posts[$digestpost->postid] = $post;
717 } else {
718 continue;
719 }
720 }
721 $discussionid = $digestpost->discussionid;
722 if (!isset($discussions[$discussionid])) {
4e445355 723 if ($discussion = $DB->get_record('forum_discussions', array('id' => $discussionid))) {
a974c799 724 $discussions[$discussionid] = $discussion;
725 } else {
726 continue;
727 }
aaf7a9dc 728 }
a974c799 729 $forumid = $discussions[$discussionid]->forum;
730 if (!isset($forums[$forumid])) {
4e445355 731 if ($forum = $DB->get_record('forum', array('id' => $forumid))) {
a974c799 732 $forums[$forumid] = $forum;
733 } else {
734 continue;
735 }
736 }
737
738 $courseid = $forums[$forumid]->course;
739 if (!isset($courses[$courseid])) {
4e445355 740 if ($course = $DB->get_record('course', array('id' => $courseid))) {
a974c799 741 $courses[$courseid] = $course;
742 } else {
743 continue;
744 }
aaf7a9dc 745 }
a974c799 746
747 if (!isset($coursemodules[$forumid])) {
748 if ($cm = get_coursemodule_from_instance('forum', $forumid, $courseid)) {
749 $coursemodules[$forumid] = $cm;
750 } else {
751 continue;
752 }
aaf7a9dc 753 }
754 $userdiscussions[$digestpost->userid][$digestpost->discussionid] = $digestpost->discussionid;
755 $discussionposts[$digestpost->discussionid][$digestpost->postid] = $digestpost->postid;
756 }
4e445355 757 $digestposts_rs->close(); /// Finished iteration, let's close the resultset
aaf7a9dc 758
759 // Data collected, start sending out emails to each user
a974c799 760 foreach ($userdiscussions as $userid => $thesediscussions) {
aaf7a9dc 761
a974c799 762 @set_time_limit(120); // terminate if processing of any account takes longer than 2 minutes
aaf7a9dc 763
e8b7114d 764 cron_setup_user();
90f4745c 765
a974c799 766 mtrace(get_string('processingdigest', 'forum', $userid), '... ');
aaf7a9dc 767
768 // First of all delete all the queue entries for this user
4e445355 769 $DB->delete_records_select('forum_queue', "userid = ? AND timemodified < ?", array($userid, $digesttime));
aaf7a9dc 770 $userto = $users[$userid];
771
0a4ac01b 772 // Override the language and timezone of the "current" user, so that
773 // mail is customised for the receiver.
e8b7114d 774 cron_setup_user($userto);
aaf7a9dc 775
df1c2c71 776 // init caches
777 $userto->viewfullnames = array();
778 $userto->canpost = array();
90f4745c 779 $userto->markposts = array();
df1c2c71 780
a974c799 781 $postsubject = get_string('digestmailsubject', 'forum', format_string($site->shortname, true));
aaf7a9dc 782
a974c799 783 $headerdata = new object();
784 $headerdata->sitename = format_string($site->fullname, true);
839f2456 785 $headerdata->userprefs = $CFG->wwwroot.'/user/edit.php?id='.$userid.'&amp;course='.$site->id;
aaf7a9dc 786
787 $posttext = get_string('digestmailheader', 'forum', $headerdata)."\n\n";
788 $headerdata->userprefs = '<a target="_blank" href="'.$headerdata->userprefs.'">'.get_string('digestmailprefs', 'forum').'</a>';
9c674431 789
78c0d909 790 $posthtml = "<head>";
78946b9b
PS
791/* foreach ($CFG->stylesheets as $stylesheet) {
792 //TODO: MDL-21120
78c0d909 793 $posthtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
78946b9b 794 }*/
449b1c1a 795 $posthtml .= "</head>\n<body id=\"email\">\n";
a0330747 796 $posthtml .= '<p>'.get_string('digestmailheader', 'forum', $headerdata).'</p><br /><hr size="1" noshade="noshade" />';
aaf7a9dc 797
a974c799 798 foreach ($thesediscussions as $discussionid) {
aaf7a9dc 799
0a4ac01b 800 @set_time_limit(120); // to be reset for each post
a974c799 801
802 $discussion = $discussions[$discussionid];
803 $forum = $forums[$discussion->forum];
804 $course = $courses[$forum->course];
805 $cm = $coursemodules[$forum->id];
65b0e537 806
9152fc99 807 //override language
e8b7114d 808 cron_setup_user($userto, $course);
9152fc99 809
df1c2c71 810 // Fill caches
811 if (!isset($userto->viewfullnames[$forum->id])) {
812 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
813 $userto->viewfullnames[$forum->id] = has_capability('moodle/site:viewfullnames', $modcontext);
814 }
8b79a625 815 if (!isset($userto->canpost[$discussion->id])) {
df1c2c71 816 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
8b79a625 817 $userto->canpost[$discussion->id] = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
df1c2c71 818 }
caadf009 819
de85c320 820 $strforums = get_string('forums', 'forum');
821 $canunsubscribe = ! forum_is_forcesubscribed($forum);
8b79a625 822 $canreply = $userto->canpost[$discussion->id];
de85c320 823
aaf7a9dc 824 $posttext .= "\n \n";
825 $posttext .= '=====================================================================';
826 $posttext .= "\n \n";
3849dae8 827 $posttext .= "$course->shortname -> $strforums -> ".format_string($forum->name,true);
aaf7a9dc 828 if ($discussion->name != $forum->name) {
c78ac798 829 $posttext .= " -> ".format_string($discussion->name,true);
caadf009 830 }
aaf7a9dc 831 $posttext .= "\n";
65b0e537 832
aaf7a9dc 833 $posthtml .= "<p><font face=\"sans-serif\">".
834 "<a target=\"_blank\" href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> -> ".
835 "<a target=\"_blank\" href=\"$CFG->wwwroot/mod/forum/index.php?id=$course->id\">$strforums</a> -> ".
3849dae8 836 "<a target=\"_blank\" href=\"$CFG->wwwroot/mod/forum/view.php?f=$forum->id\">".format_string($forum->name,true)."</a>";
aaf7a9dc 837 if ($discussion->name == $forum->name) {
838 $posthtml .= "</font></p>";
caadf009 839 } else {
c78ac798 840 $posthtml .= " -> <a target=\"_blank\" href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id\">".format_string($discussion->name,true)."</a></font></p>";
caadf009 841 }
aaf7a9dc 842 $posthtml .= '<p>';
843
e1c6dde1 844 $postsarray = $discussionposts[$discussionid];
845 sort($postsarray);
846
857b798b 847 foreach ($postsarray as $postid) {
a974c799 848 $post = $posts[$postid];
849
850 if (array_key_exists($post->userid, $users)) { // we might know him/her already
851 $userfrom = $users[$post->userid];
4e445355 852 } else if ($userfrom = $DB->get_record('user', array('id' => $post->userid))) {
df1c2c71 853 $users[$userfrom->id] = $userfrom; // fetch only once, we can add it to user list, it will be skipped anyway
854 } else {
a974c799 855 mtrace('Could not find user '.$post->userid);
aaf7a9dc 856 continue;
857 }
858
df1c2c71 859 if (!isset($userfrom->groups[$forum->id])) {
860 if (!isset($userfrom->groups)) {
861 $userfrom->groups = array();
862 $users[$userfrom->id]->groups = array();
863 }
864 $userfrom->groups[$forum->id] = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
865 $users[$userfrom->id]->groups[$forum->id] = $userfrom->groups[$forum->id];
866 }
867
857b798b 868 $userfrom->customheaders = array ("Precedence: Bulk");
869
870 if ($userto->maildigest == 2) {
aaf7a9dc 871 // Subjects only
a974c799 872 $by = new object();
aaf7a9dc 873 $by->name = fullname($userfrom);
874 $by->date = userdate($post->modified);
17dc3f3c 875 $posttext .= "\n".format_string($post->subject,true).' '.get_string("bynameondate", "forum", $by);
aaf7a9dc 876 $posttext .= "\n---------------------------------------------------------------------";
877
839f2456 878 $by->name = "<a target=\"_blank\" href=\"$CFG->wwwroot/user/view.php?id=$userfrom->id&amp;course=$course->id\">$by->name</a>";
0be4d8bf 879 $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>';
857b798b 880
881 } else {
aaf7a9dc 882 // The full treatment
0faf6791 883 $posttext .= forum_make_mail_text($course, $cm, $forum, $discussion, $post, $userfrom, $userto, true);
884 $posthtml .= forum_make_mail_post($course, $cm, $forum, $discussion, $post, $userfrom, $userto, false, $canreply, true, false);
df1c2c71 885
0a4ac01b 886 // Create an array of postid's for this user to mark as read.
90f4745c 887 if (!$CFG->forum_usermarksread) {
888 $userto->markposts[$post->id] = $post->id;
f37da850 889 }
aaf7a9dc 890 }
891 }
892 if ($canunsubscribe) {
ff9b4ea4 893 $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>";
857b798b 894 } else {
ff9b4ea4 895 $posthtml .= "\n<div class='mdl-right'><font size=\"1\">".get_string("everyoneissubscribed", "forum")."</font></div>";
aaf7a9dc 896 }
897 $posthtml .= '<hr size="1" noshade="noshade" /></p>';
caadf009 898 }
a0330747 899 $posthtml .= '</body>';
caadf009 900
6d2e6936 901 if (empty($userto->mailformat) || $userto->mailformat != 1) {
379a42cb 902 // This user DOESN'T want to receive HTML
903 $posthtml = '';
904 }
5e7f2b0b 905
b58bd1a2
AD
906 $attachment = $attachname='';
907 $usetrueaddress = true;
eac02096 908 $mailresult = email_to_user($userto, $site->shortname, $postsubject, $posttext, $posthtml, $attachment, $attachname, $usetrueaddress, $CFG->forum_replytouser);
b58bd1a2
AD
909
910 if (!$mailresult) {
b140ae85 911 mtrace("ERROR!");
aaf7a9dc 912 echo "Error: mod/forum/cron.php: Could not send out digest mail to user $userto->id ($userto->email)... not trying again.\n";
913 add_to_log($course->id, 'forum', 'mail digest error', '', '', $cm->id, $userto->id);
b6268a0e 914 } else if ($mailresult === 'emailstop') {
a974c799 915 // should not happen anymore - see check above
aaf7a9dc 916 } else {
b140ae85 917 mtrace("success.");
aaf7a9dc 918 $usermailcount++;
e3ff14ca 919
90f4745c 920 // Mark post as read if forum_usermarksread is set off
921 forum_tp_mark_posts_read($userto, $userto->markposts);
3d94772d 922 }
caadf009 923 }
caadf009 924 }
226a1d9d 925 /// We have finishied all digest emails, update $CFG->digestmailtimelast
926 set_config('digestmailtimelast', $timenow);
caadf009 927 }
928
e8b7114d 929 cron_setup_user();
de85c320 930
a974c799 931 if (!empty($usermailcount)) {
b140ae85 932 mtrace(get_string('digestsentusers', 'forum', $usermailcount));
aaf7a9dc 933 }
934
8ad64455 935 if (!empty($CFG->forum_lastreadclean)) {
f37da850 936 $timenow = time();
8ad64455 937 if ($CFG->forum_lastreadclean + (24*3600) < $timenow) {
938 set_config('forum_lastreadclean', $timenow);
8cb121cc 939 mtrace('Removing old forum read tracking info...');
f37da850 940 forum_tp_clean_read_records();
941 }
942 } else {
8ad64455 943 set_config('forum_lastreadclean', time());
f37da850 944 }
945
946
caadf009 947 return true;
948}
949
0a4ac01b 950/**
1670305d 951 * Builds and returns the body of the email notification in plain text.
952 *
df1ba0f4 953 * @global object
954 * @global object
955 * @uses CONTEXT_MODULE
1670305d 956 * @param object $course
df1ba0f4 957 * @param object $cm
1670305d 958 * @param object $forum
959 * @param object $discussion
960 * @param object $post
961 * @param object $userfrom
962 * @param object $userto
963 * @param boolean $bare
964 * @return string The email body in plain text format.
0a4ac01b 965 */
0faf6791 966function forum_make_mail_text($course, $cm, $forum, $discussion, $post, $userfrom, $userto, $bare = false) {
15f81ee3 967 global $CFG, $USER;
2b63df96 968
df1c2c71 969 if (!isset($userto->viewfullnames[$forum->id])) {
df1c2c71 970 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
971 $viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
972 } else {
973 $viewfullnames = $userto->viewfullnames[$forum->id];
974 }
975
8b79a625 976 if (!isset($userto->canpost[$discussion->id])) {
977 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
978 $canreply = forum_user_can_post($forum, $discussion, $userto, $cm, $course, $modcontext);
df1c2c71 979 } else {
8b79a625 980 $canreply = $userto->canpost[$discussion->id];
0fa18d5a 981 }
2b63df96 982
aaf7a9dc 983 $by = New stdClass;
df1c2c71 984 $by->name = fullname($userfrom, $viewfullnames);
aaf7a9dc 985 $by->date = userdate($post->modified, "", $userto->timezone);
986
987 $strbynameondate = get_string('bynameondate', 'forum', $by);
988
64762ddc 989 $strforums = get_string('forums', 'forum');
990
a9900c73 991 $canunsubscribe = ! forum_is_forcesubscribed($forum);
aaf7a9dc 992
993 $posttext = '';
994
0fa18d5a 995 if (!$bare) {
3849dae8 996 $posttext = "$course->shortname -> $strforums -> ".format_string($forum->name,true);
aaf7a9dc 997
998 if ($discussion->name != $forum->name) {
c78ac798 999 $posttext .= " -> ".format_string($discussion->name,true);
aaf7a9dc 1000 }
1001 }
1002
1003 $posttext .= "\n---------------------------------------------------------------------\n";
17dc3f3c 1004 $posttext .= format_string($post->subject,true);
0fa18d5a 1005 if ($bare) {
0be4d8bf 1006 $posttext .= " ($CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id#p$post->id)";
aaf7a9dc 1007 }
1008 $posttext .= "\n".$strbynameondate."\n";
1009 $posttext .= "---------------------------------------------------------------------\n";
e2d7687f 1010 $posttext .= format_text_email($post->message, $post->messageformat);
aaf7a9dc 1011 $posttext .= "\n\n";
0faf6791 1012 $posttext .= forum_print_attachments($post, $cm, "text");
1013
aaf7a9dc 1014 if (!$bare && $canreply) {
1015 $posttext .= "---------------------------------------------------------------------\n";
1016 $posttext .= get_string("postmailinfo", "forum", $course->shortname)."\n";
1017 $posttext .= "$CFG->wwwroot/mod/forum/post.php?reply=$post->id\n";
1018 }
1019 if (!$bare && $canunsubscribe) {
1020 $posttext .= "\n---------------------------------------------------------------------\n";
1021 $posttext .= get_string("unsubscribe", "forum");
1022 $posttext .= ": $CFG->wwwroot/mod/forum/subscribe.php?id=$forum->id\n";
1023 }
1024
1025 return $posttext;
1026}
1027
0a4ac01b 1028/**
1670305d 1029 * Builds and returns the body of the email notification in html format.
1030 *
df1ba0f4 1031 * @global object
1670305d 1032 * @param object $course
df1ba0f4 1033 * @param object $cm
1670305d 1034 * @param object $forum
1035 * @param object $discussion
1036 * @param object $post
1037 * @param object $userfrom
1038 * @param object $userto
1039 * @return string The email text in HTML format
0a4ac01b 1040 */
0faf6791 1041function forum_make_mail_html($course, $cm, $forum, $discussion, $post, $userfrom, $userto) {
aaf7a9dc 1042 global $CFG;
1043
a0288610 1044 if ($userto->mailformat != 1) { // Needs to be HTML
1045 return '';
1046 }
aaf7a9dc 1047
8b79a625 1048 if (!isset($userto->canpost[$discussion->id])) {
1049 $canreply = forum_user_can_post($forum, $discussion, $userto);
df1c2c71 1050 } else {
8b79a625 1051 $canreply = $userto->canpost[$discussion->id];
9f2ded76 1052 }
1053
a0288610 1054 $strforums = get_string('forums', 'forum');
a9900c73 1055 $canunsubscribe = ! forum_is_forcesubscribed($forum);
aaf7a9dc 1056
a0288610 1057 $posthtml = '<head>';
78946b9b
PS
1058/* foreach ($CFG->stylesheets as $stylesheet) {
1059 //TODO: MDL-21120
a0288610 1060 $posthtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
78946b9b 1061 }*/
a0288610 1062 $posthtml .= '</head>';
f2379d2d 1063 $posthtml .= "\n<body id=\"email\">\n\n";
aaf7a9dc 1064
f2379d2d 1065 $posthtml .= '<div class="navbar">'.
a0288610 1066 '<a target="_blank" href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">'.$course->shortname.'</a> &raquo; '.
1067 '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/index.php?id='.$course->id.'">'.$strforums.'</a> &raquo; '.
1068 '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'">'.format_string($forum->name,true).'</a>';
1069 if ($discussion->name == $forum->name) {
1070 $posthtml .= '</div>';
aaf7a9dc 1071 } else {
a0288610 1072 $posthtml .= ' &raquo; <a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion->id.'">'.
1073 format_string($discussion->name,true).'</a></div>';
aaf7a9dc 1074 }
0faf6791 1075 $posthtml .= forum_make_mail_post($course, $cm, $forum, $discussion, $post, $userfrom, $userto, false, $canreply, true, false);
a0288610 1076
1077 if ($canunsubscribe) {
85db96c5 1078 $posthtml .= '<hr /><div class="mdl-align unsubscribelink">
739da48c 1079 <a href="'.$CFG->wwwroot.'/mod/forum/subscribe.php?id='.$forum->id.'">'.get_string('unsubscribe', 'forum').'</a>&nbsp;
1080 <a href="'.$CFG->wwwroot.'/mod/forum/unsubscribeall.php">'.get_string('unsubscribeall', 'forum').'</a></div>';
a0288610 1081 }
1082
f2379d2d 1083 $posthtml .= '</body>';
1084
a0288610 1085 return $posthtml;
aaf7a9dc 1086}
1670305d 1087
1088
0a4ac01b 1089/**
13bbe067 1090 *
1670305d 1091 * @param object $course
1092 * @param object $user
1093 * @param object $mod TODO this is not used in this function, refactor
1094 * @param object $forum
1095 * @return object A standard object with 2 variables: info (number of posts for this user) and time (last modified)
0a4ac01b 1096 */
caadf009 1097function forum_user_outline($course, $user, $mod, $forum) {
1a96363a
NC
1098 global $CFG;
1099 require_once("$CFG->libdir/gradelib.php");
1100 $grades = grade_get_grades($course->id, 'mod', 'forum', $forum->id, $user->id);
1101 if (empty($grades->items[0]->grades)) {
1102 $grade = false;
1103 } else {
1104 $grade = reset($grades->items[0]->grades);
1105 }
1106
1107 $count = forum_count_user_posts($forum->id, $user->id);
1108
1109 if ($count && $count->postcount > 0) {
1110 $result = new object();
1111 $result->info = get_string("numposts", "forum", $count->postcount);
1112 $result->time = $count->lastpost;
1113 if ($grade) {
1114 $result->info .= ', ' . get_string('grade') . ': ' . $grade->str_long_grade;
90f4745c 1115 }
1a96363a
NC
1116 return $result;
1117 } else if ($grade) {
1118 $result = new object();
1119 $result->info = get_string('grade') . ': ' . $grade->str_long_grade;
1120 $result->time = $grade->dategraded;
1121 return $result;
caadf009 1122 }
1123 return NULL;
1124}
1125
1126
0a4ac01b 1127/**
df1ba0f4 1128 * @global object
1129 * @global object
1130 * @param object $coure
1131 * @param object $user
1132 * @param object $mod
1133 * @param object $forum
0a4ac01b 1134 */
caadf009 1135function forum_user_complete($course, $user, $mod, $forum) {
1a96363a
NC
1136 global $CFG,$USER, $OUTPUT;
1137 require_once("$CFG->libdir/gradelib.php");
1138
1139 $grades = grade_get_grades($course->id, 'mod', 'forum', $forum->id, $user->id);
1140 if (!empty($grades->items[0]->grades)) {
1141 $grade = reset($grades->items[0]->grades);
1142 echo $OUTPUT->container(get_string('grade').': '.$grade->str_long_grade);
1143 if ($grade->str_feedback) {
1144 echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
1145 }
1146 }
caadf009 1147
1f48942e 1148 if ($posts = forum_get_user_posts($forum->id, $user->id)) {
e3ff14ca 1149
65bcf17b 1150 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
12e57b92 1151 print_error('invalidcoursemodule');
65bcf17b 1152 }
90f4745c 1153 $discussions = forum_get_user_involved_discussions($forum->id, $user->id);
65bcf17b 1154
1155 foreach ($posts as $post) {
5e7f2b0b 1156 if (!isset($discussions[$post->discussion])) {
90f4745c 1157 continue;
1158 }
7a8d8f22 1159 $discussion = $discussions[$post->discussion];
5e7f2b0b 1160
63e87951 1161 forum_print_post($post, $discussion, $forum, $cm, $course, false, false, false);
5e7f2b0b 1162 }
caadf009 1163 } else {
41905731 1164 echo "<p>".get_string("noposts", "forum")."</p>";
caadf009 1165 }
caadf009 1166}
1167
c38965fb 1168
1169
1170
5e7f2b0b 1171
1172
0a4ac01b 1173/**
df1ba0f4 1174 * @global object
1175 * @global object
1176 * @global object
1177 * @param array $courses
1178 * @param array $htmlarray
0a4ac01b 1179 */
185cfb09 1180function forum_print_overview($courses,&$htmlarray) {
261c6ef0 1181 global $USER, $CFG, $DB, $SESSION;
493f0820 1182
c4f1e62c 1183 //$LIKE = $DB->sql_ilike();//no longer using like in queries. MDL-20578
9cba7a8c 1184
185cfb09 1185 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
1186 return array();
1187 }
f8716988 1188
185cfb09 1189 if (!$forums = get_all_instances_in_courses('forum',$courses)) {
f8716988 1190 return;
1191 }
185cfb09 1192
5aa23eea 1193
f8716988 1194 // get all forum logs in ONE query (much better!)
4e445355 1195 $params = array();
1196 $sql = "SELECT instance,cmid,l.course,COUNT(l.id) as count FROM {log} l "
1197 ." JOIN {course_modules} cm ON cm.id = cmid "
185cfb09 1198 ." WHERE (";
1199 foreach ($courses as $course) {
4e445355 1200 $sql .= '(l.course = ? AND l.time > ?) OR ';
1201 $params[] = $course->id;
1202 $params[] = $course->lastaccess;
185cfb09 1203 }
1204 $sql = substr($sql,0,-3); // take off the last OR
1205
b55d0869 1206 $sql .= ") AND l.module = 'forum' AND action = 'add post' "
4e445355 1207 ." AND userid != ? GROUP BY cmid,l.course,instance";
1208
1209 $params[] = $USER->id;
2b63df96 1210
4e445355 1211 if (!$new = $DB->get_records_sql($sql, $params)) {
185cfb09 1212 $new = array(); // avoid warnings
1213 }
2b63df96 1214
185cfb09 1215 // also get all forum tracking stuff ONCE.
1216 $trackingforums = array();
1217 foreach ($forums as $forum) {
1218 if (forum_tp_can_track_forums($forum)) {
1219 $trackingforums[$forum->id] = $forum;
1220 }
1221 }
2b63df96 1222
185cfb09 1223 if (count($trackingforums) > 0) {
1224 $cutoffdate = isset($CFG->forum_oldpostdays) ? (time() - ($CFG->forum_oldpostdays*24*60*60)) : 0;
1225 $sql = 'SELECT d.forum,d.course,COUNT(p.id) AS count '.
4e445355 1226 ' FROM {forum_posts} p '.
1227 ' JOIN {forum_discussions} d ON p.discussion = d.id '.
1228 ' LEFT JOIN {forum_read} r ON r.postid = p.id AND r.userid = ? WHERE (';
1229 $params = array($USER->id);
1230
d3553951 1231 foreach ($trackingforums as $track) {
4e445355 1232 $sql .= '(d.forum = ? AND (d.groupid = -1 OR d.groupid = 0 OR d.groupid = ?)) OR ';
1233 $params[] = $track->id;
261c6ef0 1234 if (isset($SESSION->currentgroup[$track->course])) {
1235 $groupid = $SESSION->currentgroup[$track->course];
1236 } else {
1237 $groupid = groups_get_all_groups($track->course, $USER->id);
1238 if (is_array($groupid)) {
1239 $groupid = array_shift(array_keys($groupid));
1240 $SESSION->currentgroup[$track->course] = $groupid;
1241 } else {
1242 $groupid = 0;
1243 }
1244 }
1245 $params[] = $groupid;
185cfb09 1246 }
1247 $sql = substr($sql,0,-3); // take off the last OR
4e445355 1248 $sql .= ') AND p.modified >= ? AND r.id is NULL GROUP BY d.forum,d.course';
1249 $params[] = $cutoffdate;
185cfb09 1250
4e445355 1251 if (!$unread = $DB->get_records_sql($sql, $params)) {
185cfb09 1252 $unread = array();
1253 }
1254 } else {
1255 $unread = array();
95d71ad3 1256 }
185cfb09 1257
9cba7a8c 1258 if (empty($unread) and empty($new)) {
1259 return;
1260 }
1261
1262 $strforum = get_string('modulename','forum');
1263 $strnumunread = get_string('overviewnumunread','forum');
1264 $strnumpostssince = get_string('overviewnumpostssince','forum');
1265
f8716988 1266 foreach ($forums as $forum) {
185cfb09 1267 $str = '';
f8716988 1268 $count = 0;
185cfb09 1269 $thisunread = 0;
f8716988 1270 $showunread = false;
1271 // either we have something from logs, or trackposts, or nothing.
1272 if (array_key_exists($forum->id, $new) && !empty($new[$forum->id])) {
1273 $count = $new[$forum->id]->count;
90558ec4 1274 }
185cfb09 1275 if (array_key_exists($forum->id,$unread)) {
1276 $thisunread = $unread[$forum->id]->count;
f8716988 1277 $showunread = true;
0d6b9d4f 1278 }
185cfb09 1279 if ($count > 0 || $thisunread > 0) {
e23800b7 1280 $str .= '<div class="overview forum"><div class="name">'.$strforum.': <a title="'.$strforum.'" href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'">'.
1281 $forum->name.'</a></div>';
1282 $str .= '<div class="info">';
1283 $str .= $count.' '.$strnumpostssince;
f8716988 1284 if (!empty($showunread)) {
e23800b7 1285 $str .= '<br />'.$thisunread .' '.$strnumunread;
f8716988 1286 }
e23800b7 1287 $str .= '</div></div>';
f8716988 1288 }
2b63df96 1289 if (!empty($str)) {
185cfb09 1290 if (!array_key_exists($forum->course,$htmlarray)) {
1291 $htmlarray[$forum->course] = array();
1292 }
1293 if (!array_key_exists('forum',$htmlarray[$forum->course])) {
1294 $htmlarray[$forum->course]['forum'] = ''; // initialize, avoid warnings
1295 }
1296 $htmlarray[$forum->course]['forum'] .= $str;
1297 }
2b63df96 1298 }
0d6b9d4f 1299}
1300
0a4ac01b 1301/**
1302 * Given a course and a date, prints a summary of all the new
1303 * messages posted in the course since that date
df1ba0f4 1304 *
1305 * @global object
1306 * @global object
1307 * @global object
1308 * @uses CONTEXT_MODULE
1309 * @uses VISIBLEGROUPS
90f4745c 1310 * @param object $course
1311 * @param bool $viewfullnames capability
1312 * @param int $timestart
1313 * @return bool success
0a4ac01b 1314 */
dd97c328 1315function forum_print_recent_activity($course, $viewfullnames, $timestart) {
cb860491 1316 global $CFG, $USER, $DB, $OUTPUT;
caadf009 1317
dd97c328 1318 // do not use log table if possible, it may be huge and is expensive to join with other tables
caadf009 1319
4e445355 1320 if (!$posts = $DB->get_records_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
1321 d.timestart, d.timeend, d.userid AS duserid,
1322 u.firstname, u.lastname, u.email, u.picture
1323 FROM {forum_posts} p
1324 JOIN {forum_discussions} d ON d.id = p.discussion
1325 JOIN {forum} f ON f.id = d.forum
1326 JOIN {user} u ON u.id = p.userid
1327 WHERE p.created > ? AND f.course = ?
1328 ORDER BY p.id ASC", array($timestart, $course->id))) { // order by initial posting date
dd97c328 1329 return false;
1b5910c4 1330 }
1331
dd97c328 1332 $modinfo =& get_fast_modinfo($course);
dcde9f02 1333
dd97c328 1334 $groupmodes = array();
1335 $cms = array();
d05956ac 1336
dd97c328 1337 $strftimerecent = get_string('strftimerecent');
d05956ac 1338
dd97c328 1339 $printposts = array();
1340 foreach ($posts as $post) {
1341 if (!isset($modinfo->instances['forum'][$post->forum])) {
1342 // not visible
1343 continue;
1344 }
1345 $cm = $modinfo->instances['forum'][$post->forum];
1346 if (!$cm->uservisible) {
1347 continue;
1348 }
6b7de0bb 1349 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1350
1351 if (!has_capability('mod/forum:viewdiscussion', $context)) {
1352 continue;
1353 }
583b57b4 1354
dd97c328 1355 if (!empty($CFG->forum_enabletimedposts) and $USER->id != $post->duserid
1356 and (($post->timestart > 0 and $post->timestart > time()) or ($post->timeend > 0 and $post->timeend < time()))) {
6b7de0bb 1357 if (!has_capability('mod/forum:viewhiddentimedposts', $context)) {
dd97c328 1358 continue;
ac1d9a22 1359 }
dd97c328 1360 }
583b57b4 1361
dd97c328 1362 $groupmode = groups_get_activity_groupmode($cm, $course);
b91d6dcd 1363
dd97c328 1364 if ($groupmode) {
6b7de0bb 1365 if ($post->groupid == -1 or $groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
dd97c328 1366 // oki (Open discussions have groupid -1)
1367 } else {
1368 // separate mode
1369 if (isguestuser()) {
1370 // shortcut
1371 continue;
1372 }
2b63df96 1373
dd97c328 1374 if (is_null($modinfo->groups)) {
1375 $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo
1b5910c4 1376 }
ac1d9a22 1377
dd97c328 1378 if (!array_key_exists($post->groupid, $modinfo->groups[0])) {
1379 continue;
1380 }
ac1d9a22 1381 }
dd97c328 1382 }
8f7dc7f1 1383
dd97c328 1384 $printposts[] = $post;
1385 }
1386 unset($posts);
8f7dc7f1 1387
dd97c328 1388 if (!$printposts) {
1389 return false;
1390 }
1391
cb860491 1392 echo $OUTPUT->heading(get_string('newforumposts', 'forum').':', 3);
dd97c328 1393 echo "\n<ul class='unlist'>\n";
1394
1395 foreach ($printposts as $post) {
1396 $subjectclass = empty($post->parent) ? ' bold' : '';
1397
1398 echo '<li><div class="head">'.
1399 '<div class="date">'.userdate($post->modified, $strftimerecent).'</div>'.
1400 '<div class="name">'.fullname($post, $viewfullnames).'</div>'.
1401 '</div>';
1402 echo '<div class="info'.$subjectclass.'">';
1403 if (empty($post->parent)) {
1404 echo '"<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
1405 } else {
1406 echo '"<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'&amp;parent='.$post->parent.'#p'.$post->id.'">';
caadf009 1407 }
dd97c328 1408 $post->subject = break_up_long_words(format_string($post->subject, true));
1409 echo $post->subject;
1410 echo "</a>\"</div></li>\n";
caadf009 1411 }
dd97c328 1412
1306c5ea 1413 echo "</ul>\n";
dd97c328 1414
1415 return true;
caadf009 1416}
1417
353228d8 1418/**
1419 * Return grade for given user or all users.
1420 *
df1ba0f4 1421 * @global object
1422 * @global object
1423 * @param object $forum
353228d8 1424 * @param int $userid optional user id, 0 means all users
1425 * @return array array of grades, false if none
1426 */
612607bd 1427function forum_get_user_grades($forum, $userid=0) {
63e87951 1428 global $CFG;
df997f84 1429
63e87951
AD
1430 require_once($CFG->dirroot.'/rating/lib.php');
1431 $rm = new rating_manager();
df997f84 1432
63e87951 1433 $ratingoptions = new stdclass();
353228d8 1434
63e87951
AD
1435 //need these to work backwards to get a context id. Is there a better way to get contextid from a module instance?
1436 $ratingoptions->modulename = 'forum';
1437 $ratingoptions->moduleid = $forum->id;
1438 //$ratingoptions->cmidnumber = $forum->cmidnumber;
4e445355 1439
63e87951
AD
1440 $ratingoptions->userid = $userid;
1441 $ratingoptions->aggregationmethod = $forum->assessed;
1442 $ratingoptions->scaleid = $forum->scale;
1443 $ratingoptions->itemtable = 'forum_posts';
1444 $ratingoptions->itemtableusercolumn = 'userid';
353228d8 1445
63e87951 1446 return $rm->get_user_grades($ratingoptions);
353228d8 1447}
caadf009 1448
0a4ac01b 1449/**
775f811a 1450 * Update activity grades
353228d8 1451 *
df1ba0f4 1452 * @global object
1453 * @global object
775f811a 1454 * @param object $forum
1455 * @param int $userid specific user only, 0 means all
6b7de0bb 1456 * @param boolean $nullifnone return null if grade does not exist
90f4745c 1457 * @return void
0a4ac01b 1458 */
775f811a 1459function forum_update_grades($forum, $userid=0, $nullifnone=true) {
4e445355 1460 global $CFG, $DB;
775f811a 1461 require_once($CFG->libdir.'/gradelib.php');
caadf009 1462
775f811a 1463 if (!$forum->assessed) {
1464 forum_grade_item_update($forum);
02ebf404 1465
775f811a 1466 } else if ($grades = forum_get_user_grades($forum, $userid)) {
1467 forum_grade_item_update($forum, $grades);
eafb9d9e 1468
775f811a 1469 } else if ($userid and $nullifnone) {
1470 $grade = new object();
1471 $grade->userid = $userid;
1472 $grade->rawgrade = NULL;
1473 forum_grade_item_update($forum, $grade);
02ebf404 1474
353228d8 1475 } else {
775f811a 1476 forum_grade_item_update($forum);
1477 }
1478}
1479
1480/**
1481 * Update all grades in gradebook.
df1ba0f4 1482 * @global object
775f811a 1483 */
1484function forum_upgrade_grades() {
1485 global $DB;
1486
1487 $sql = "SELECT COUNT('x')
1488 FROM {forum} f, {course_modules} cm, {modules} m
1489 WHERE m.name='forum' AND m.id=cm.module AND cm.instance=f.id";
1490 $count = $DB->count_records_sql($sql);
1491
1492 $sql = "SELECT f.*, cm.idnumber AS cmidnumber, f.course AS courseid
1493 FROM {forum} f, {course_modules} cm, {modules} m
1494 WHERE m.name='forum' AND m.id=cm.module AND cm.instance=f.id";
1495 if ($rs = $DB->get_recordset_sql($sql)) {
775f811a 1496 $pbar = new progress_bar('forumupgradegrades', 500, true);
1497 $i=0;
1498 foreach ($rs as $forum) {
1499 $i++;
1500 upgrade_set_timeout(60*5); // set up timeout, may also abort execution
1501 forum_update_grades($forum, 0, false);
1502 $pbar->update($i, $count, "Updating Forum grades ($i/$count).");
caadf009 1503 }
775f811a 1504 $rs->close();
353228d8 1505 }
1506}
1507
1508/**
612607bd 1509 * Create/update grade item for given forum
353228d8 1510 *
df1ba0f4 1511 * @global object
1512 * @uses GRADE_TYPE_NONE
1513 * @uses GRADE_TYPE_VALUE
1514 * @uses GRADE_TYPE_SCALE
353228d8 1515 * @param object $forum object with extra cmidnumber
df1ba0f4 1516 * @param mixed $grades optional array/object of grade(s); 'reset' means reset grades in gradebook
612607bd 1517 * @return int 0 if ok
353228d8 1518 */
0b5a80a1 1519function forum_grade_item_update($forum, $grades=NULL) {
612607bd 1520 global $CFG;
1521 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
1522 require_once($CFG->libdir.'/gradelib.php');
353228d8 1523 }
1524
612607bd 1525 $params = array('itemname'=>$forum->name, 'idnumber'=>$forum->cmidnumber);
353228d8 1526
5980d52f 1527 if (!$forum->assessed or $forum->scale == 0) {
612607bd 1528 $params['gradetype'] = GRADE_TYPE_NONE;
353228d8 1529
1530 } else if ($forum->scale > 0) {
1531 $params['gradetype'] = GRADE_TYPE_VALUE;
1532 $params['grademax'] = $forum->scale;
1533 $params['grademin'] = 0;
1534
1535 } else if ($forum->scale < 0) {
1536 $params['gradetype'] = GRADE_TYPE_SCALE;
1537 $params['scaleid'] = -$forum->scale;
1538 }
1539
0b5a80a1 1540 if ($grades === 'reset') {
1541 $params['reset'] = true;
1542 $grades = NULL;
1543 }
1544
1545 return grade_update('mod/forum', $forum->course, 'mod', 'forum', $forum->id, 0, $grades, $params);
353228d8 1546}
1547
1548/**
1549 * Delete grade item for given forum
1550 *
df1ba0f4 1551 * @global object
353228d8 1552 * @param object $forum object
1553 * @return object grade_item
1554 */
1555function forum_grade_item_delete($forum) {
612607bd 1556 global $CFG;
1557 require_once($CFG->libdir.'/gradelib.php');
1558
b67ec72f 1559 return grade_update('mod/forum', $forum->course, 'mod', 'forum', $forum->id, 0, NULL, array('deleted'=>1));
caadf009 1560}
1561
353228d8 1562
0a4ac01b 1563/**
1564 * Returns the users with data in one forum
63e87951 1565 * (users with records in forum_subscriptions, forum_posts, students)
df1ba0f4 1566 *
1567 * @global object
1568 * @global object
90f4745c 1569 * @param int $forumid
1570 * @return mixed array or false if none
0a4ac01b 1571 */
05855091 1572function forum_get_participants($forumid) {
05855091 1573
4e445355 1574 global $CFG, $DB;
05855091 1575
1576 //Get students from forum_subscriptions
4e445355 1577 $st_subscriptions = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
1578 FROM {user} u,
1579 {forum_subscriptions} s
1580 WHERE s.forum = ? AND
1581 u.id = s.userid", array($forumid));
05855091 1582 //Get students from forum_posts
4e445355 1583 $st_posts = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
1584 FROM {user} u,
1585 {forum_discussions} d,
1586 {forum_posts} p
1587 WHERE d.forum = ? AND
1588 p.discussion = d.id AND
1589 u.id = p.userid", array($forumid));
05855091 1590
63e87951 1591 //Get students from the ratings table
4e445355 1592 $st_ratings = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
1593 FROM {user} u,
1594 {forum_discussions} d,
1595 {forum_posts} p,
63e87951 1596 {ratings} r
4e445355 1597 WHERE d.forum = ? AND
1598 p.discussion = d.id AND
1599 r.post = p.id AND
1600 u.id = r.userid", array($forumid));
05855091 1601
1602 //Add st_posts to st_subscriptions
1603 if ($st_posts) {
1604 foreach ($st_posts as $st_post) {
1605 $st_subscriptions[$st_post->id] = $st_post;
1606 }
1607 }
1608 //Add st_ratings to st_subscriptions
1609 if ($st_ratings) {
1610 foreach ($st_ratings as $st_rating) {
1611 $st_subscriptions[$st_rating->id] = $st_rating;
1612 }
1613 }
1614 //Return st_subscriptions array (it contains an array of unique users)
1615 return ($st_subscriptions);
1616}
caadf009 1617
0a4ac01b 1618/**
90f4745c 1619 * This function returns if a scale is being used by one forum
df1ba0f4 1620 *
1621 * @global object
90f4745c 1622 * @param int $forumid
1623 * @param int $scaleid negative number
1624 * @return bool
0a4ac01b 1625 */
0f1a97c2 1626function forum_scale_used ($forumid,$scaleid) {
4e445355 1627 global $DB;
0f1a97c2 1628 $return = false;
65b0e537 1629
4e445355 1630 $rec = $DB->get_record("forum",array("id" => "$forumid","scale" => "-$scaleid"));
65b0e537 1631
fa22fd5f 1632 if (!empty($rec) && !empty($scaleid)) {
0f1a97c2 1633 $return = true;
1634 }
65b0e537 1635
0f1a97c2 1636 return $return;
1637}
1638
85c9ebb9 1639/**
1640 * Checks if scale is being used by any instance of forum
1641 *
1642 * This is used to find out if scale used anywhere
df1ba0f4 1643 *
1644 * @global object
85c9ebb9 1645 * @param $scaleid int
1646 * @return boolean True if the scale is used by any forum
1647 */
1648function forum_scale_used_anywhere($scaleid) {
4e445355 1649 global $DB;
1650 if ($scaleid and $DB->record_exists('forum', array('scale' => -$scaleid))) {
85c9ebb9 1651 return true;
1652 } else {
1653 return false;
1654 }
1655}
1656
0a4ac01b 1657// SQL FUNCTIONS ///////////////////////////////////////////////////////////
9fa49e22 1658
0a4ac01b 1659/**
1660 * Gets a post with all info ready for forum_print_post
1661 * Most of these joins are just to get the forum id
df1ba0f4 1662 *
1663 * @global object
1664 * @global object
90f4745c 1665 * @param int $postid
1666 * @return mixed array of posts or false
0a4ac01b 1667 */
1f48942e 1668function forum_get_post_full($postid) {
4e445355 1669 global $CFG, $DB;
1f48942e 1670
4e445355 1671 return $DB->get_record_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
1672 FROM {forum_posts} p
1673 JOIN {forum_discussions} d ON p.discussion = d.id
1674 LEFT JOIN {user} u ON p.userid = u.id
1675 WHERE p.id = ?", array($postid));
1f48942e 1676}
1677
0a4ac01b 1678/**
1679 * Gets posts with all info ready for forum_print_post
1680 * We pass forumid in because we always know it so no need to make a
1681 * complicated join to find it out.
df1ba0f4 1682 *
1683 * @global object
1684 * @global object
90f4745c 1685 * @return mixed array of posts or false
0a4ac01b 1686 */
77efef3e 1687function forum_get_discussion_posts($discussion, $sort, $forumid) {
4e445355 1688 global $CFG, $DB;
1f48942e 1689
4e445355 1690 return $DB->get_records_sql("SELECT p.*, $forumid AS forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
1691 FROM {forum_posts} p
1692 LEFT JOIN {user} u ON p.userid = u.id
1693 WHERE p.discussion = ?
1694 AND p.parent > 0 $sort", array($discussion));
1f48942e 1695}
1696
65bcf17b 1697/**
1698 * Gets all posts in discussion including top parent.
df1ba0f4 1699 *
1700 * @global object
1701 * @global object
1702 * @global object
90f4745c 1703 * @param int $discussionid
1704 * @param string $sort
1705 * @param bool $tracking does user track the forum?
1706 * @return array of posts
65bcf17b 1707 */
90f4745c 1708function forum_get_all_discussion_posts($discussionid, $sort, $tracking=false) {
4e445355 1709 global $CFG, $DB, $USER;
65bcf17b 1710
3c2bf848 1711 $tr_sel = "";
1712 $tr_join = "";
4e445355 1713 $params = array();
3c2bf848 1714
90f4745c 1715 if ($tracking) {
1716 $now = time();
1717 $cutoffdate = $now - ($CFG->forum_oldpostdays * 24 * 3600);
1718 $tr_sel = ", fr.id AS postread";
4e445355 1719 $tr_join = "LEFT JOIN {forum_read} fr ON (fr.postid = p.id AND fr.userid = ?)";
1720 $params[] = $USER->id;
90f4745c 1721 }
1722
4e445355 1723 $params[] = $discussionid;
1724 if (!$posts = $DB->get_records_sql("SELECT p.*, u.firstname, u.lastname, u.email, u.picture, u.imagealt $tr_sel
1725 FROM {forum_posts} p
1726 LEFT JOIN {user} u ON p.userid = u.id
90f4745c 1727 $tr_join
4e445355 1728 WHERE p.discussion = ?
1729 ORDER BY $sort", $params)) {
65bcf17b 1730 return array();
1731 }
1732
1733 foreach ($posts as $pid=>$p) {
90f4745c 1734 if ($tracking) {
1735 if (forum_tp_is_post_old($p)) {
6b7de0bb 1736 $posts[$pid]->postread = true;
90f4745c 1737 }
1738 }
65bcf17b 1739 if (!$p->parent) {
1740 continue;
1741 }
1742 if (!isset($posts[$p->parent])) {
1743 continue; // parent does not exist??
1744 }
1745 if (!isset($posts[$p->parent]->children)) {
1746 $posts[$p->parent]->children = array();
1747 }
1748 $posts[$p->parent]->children[$pid] =& $posts[$pid];
1749 }
1750
1751 return $posts;
1752}
1753
0a4ac01b 1754/**
1755 * Gets posts with all info ready for forum_print_post
1756 * We pass forumid in because we always know it so no need to make a
1757 * complicated join to find it out.
df1ba0f4 1758 *
1759 * @global object
1760 * @global object
1761 * @param int $parent
1762 * @param int $forumid
1763 * @return array
0a4ac01b 1764 */
77efef3e 1765function forum_get_child_posts($parent, $forumid) {
4e445355 1766 global $CFG, $DB;
1f48942e 1767
4e445355 1768 return $DB->get_records_sql("SELECT p.*, $forumid AS forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
1769 FROM {forum_posts} p
1770 LEFT JOIN {user} u ON p.userid = u.id
1771 WHERE p.parent = ?
1772 ORDER BY p.created ASC", array($parent));
1f48942e 1773}
1774
42fb3c85 1775/**
1776 * An array of forum objects that the user is allowed to read/search through.
df1ba0f4 1777 *
1778 * @global object
1779 * @global object
1780 * @global object
1781 * @param int $userid
1782 * @param int $courseid if 0, we look for forums throughout the whole site.
42fb3c85 1783 * @return array of forum objects, or false if no matches
1784 * Forum objects have the following attributes:
1785 * id, type, course, cmid, cmvisible, cmgroupmode, accessallgroups,
1786 * viewhiddentimedposts
1787 */
1788function forum_get_readable_forums($userid, $courseid=0) {
2b63df96 1789
4e445355 1790 global $CFG, $DB, $USER;
6b7de0bb 1791 require_once($CFG->dirroot.'/course/lib.php');
2b63df96 1792
4e445355 1793 if (!$forummod = $DB->get_record('modules', array('name' => 'forum'))) {
12e57b92 1794 print_error('notinstalled', 'forum');
42fb3c85 1795 }
2b63df96 1796
42fb3c85 1797 if ($courseid) {
4e445355 1798 $courses = $DB->get_records('course', array('id' => $courseid));
42fb3c85 1799 } else {
65bcf17b 1800 // If no course is specified, then the user can see SITE + his courses.
4e445355 1801 $courses1 = $DB->get_records('course', array('id' => SITEID));
df997f84 1802 $courses2 = enrol_get_users_courses($userid, true);
6155150c 1803 $courses = array_merge($courses1, $courses2);
42fb3c85 1804 }
1805 if (!$courses) {
6b7de0bb 1806 return array();
42fb3c85 1807 }
1808
1809 $readableforums = array();
2b63df96 1810
6527b5c2 1811 foreach ($courses as $course) {
1812
6b7de0bb 1813 $modinfo =& get_fast_modinfo($course);
1814 if (is_null($modinfo->groups)) {
1815 $modinfo->groups = groups_get_user_groups($course->id, $userid);
42fb3c85 1816 }
2b63df96 1817
6b7de0bb 1818 if (empty($modinfo->instances['forum'])) {
1819 // hmm, no forums?
1820 continue;
1821 }
2b63df96 1822
4e445355 1823 $courseforums = $DB->get_records('forum', array('course' => $course->id));
2b63df96 1824
6b7de0bb 1825 foreach ($modinfo->instances['forum'] as $forumid => $cm) {
1826 if (!$cm->uservisible or !isset($courseforums[$forumid])) {
1827 continue;
1828 }
1829 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1830 $forum = $courseforums[$forumid];
d50704bf 1831
6b7de0bb 1832 if (!has_capability('mod/forum:viewdiscussion', $context)) {
1833 continue;
1834 }
6527b5c2 1835
6b7de0bb 1836 /// group access
1837 if (groups_get_activity_groupmode($cm, $course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
1838 if (is_null($modinfo->groups)) {
1839 $modinfo->groups = groups_get_user_groups($course->id, $USER->id);
1840 }
98da6021 1841 if (isset($modinfo->groups[$cm->groupingid])) {
6b7de0bb 1842 $forum->onlygroups = $modinfo->groups[$cm->groupingid];
1843 $forum->onlygroups[] = -1;
1844 } else {
1845 $forum->onlygroups = array(-1);
1846 }
1847 }
2b63df96 1848
6b7de0bb 1849 /// hidden timed discussions
1850 $forum->viewhiddentimedposts = true;
1851 if (!empty($CFG->forum_enabletimedposts)) {
1852 if (!has_capability('mod/forum:viewhiddentimedposts', $context)) {
1853 $forum->viewhiddentimedposts = false;
1854 }
1855 }
d50704bf 1856
6b7de0bb 1857 /// qanda access
1858 if ($forum->type == 'qanda'
1859 && !has_capability('mod/forum:viewqandawithoutposting', $context)) {
2b63df96 1860
6b7de0bb 1861 // We need to check whether the user has posted in the qanda forum.
1862 $forum->onlydiscussions = array(); // Holds discussion ids for the discussions
1863 // the user is allowed to see in this forum.
1864 if ($discussionspostedin = forum_discussions_user_has_posted_in($forum->id, $USER->id)) {
1865 foreach ($discussionspostedin as $d) {
1866 $forum->onlydiscussions[] = $d->id;
d50704bf 1867 }
42fb3c85 1868 }
1869 }
6b7de0bb 1870
1871 $readableforums[$forum->id] = $forum;
42fb3c85 1872 }
6b7de0bb 1873
1874 unset($modinfo);
1875
42fb3c85 1876 } // End foreach $courses
2b63df96 1877
42fb3c85 1878 return $readableforums;
1879}
1880
bbbf2d40 1881/**
1882 * Returns a list of posts found using an array of search terms.
df1ba0f4 1883 *
1884 * @global object
1885 * @global object
1886 * @global object
1887 * @param array $searchterms array of search terms, e.g. word +word -word
1888 * @param int $courseid if 0, we search through the whole site
1889 * @param int $limitfrom
1890 * @param int $limitnum
1891 * @param int &$totalcount
1892 * @param string $extrasql
1893 * @return array|bool Array of posts found or false
42fb3c85 1894 */
2b63df96 1895function forum_search_posts($searchterms, $courseid=0, $limitfrom=0, $limitnum=50,
42fb3c85 1896 &$totalcount, $extrasql='') {
4e445355 1897 global $CFG, $DB, $USER;
42fb3c85 1898 require_once($CFG->libdir.'/searchlib.php');
1899
1900 $forums = forum_get_readable_forums($USER->id, $courseid);
2b63df96 1901
67875aa1 1902 if (count($forums) == 0) {
6b7de0bb 1903 $totalcount = 0;
67875aa1 1904 return false;
1905 }
42fb3c85 1906
6b7de0bb 1907 $now = round(time(), -2); // db friendly
1908
1909 $fullaccess = array();
1910 $where = array();
4e445355 1911 $params = array();
6b7de0bb 1912
1913 foreach ($forums as $forumid => $forum) {
1914 $select = array();
1915
1916 if (!$forum->viewhiddentimedposts) {
004efe66 1917 $select[] = "(d.userid = :userid OR (d.timestart < : AND (d.timeend = 0 OR d.timeend > :timeend)))";
1918 $params = array('userid'=>$USER->id, 'timestart'=>$now, 'timeend'=>$now);
42fb3c85 1919 }
6b7de0bb 1920
ad9c22aa 1921 $cm = get_coursemodule_from_instance('forum', $forumid);
1922 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1923
1924 if ($forum->type == 'qanda'
1925 && !has_capability('mod/forum:viewqandawithoutposting', $context)) {
6b7de0bb 1926 if (!empty($forum->onlydiscussions)) {
004efe66 1927 list($discussionid_sql, $discussionid_params) = $DB->get_in_or_equal($forum->onlydiscussions, SQL_PARAMS_NAMED, 'qanda0');
4e445355 1928 $params = array_merge($params, $discussionid_params);
1929 $select[] = "(d.id $discussionid_sql OR p.parent = 0)";
d50704bf 1930 } else {
6b7de0bb 1931 $select[] = "p.parent = 0";
d50704bf 1932 }
1933 }
6b7de0bb 1934
1935 if (!empty($forum->onlygroups)) {
004efe66 1936 list($groupid_sql, $groupid_params) = $DB->get_in_or_equal($forum->onlygroups, SQL_PARAMS_NAMED, 'grps0');
4e445355 1937 $params = array_merge($params, $groupid_params);
1938 $select[] = "d.groupid $groupid_sql";
42fb3c85 1939 }
6b7de0bb 1940
1941 if ($select) {
1942 $selects = implode(" AND ", $select);
004efe66 1943 $where[] = "(d.forum = :forum AND $selects)";
1944 $params['forum'] = $forumid;
6b7de0bb 1945 } else {
1946 $fullaccess[] = $forumid;
1947 }
1948 }
1949
1950 if ($fullaccess) {
004efe66 1951 list($fullid_sql, $fullid_params) = $DB->get_in_or_equal($fullaccess, SQL_PARAMS_NAMED, 'fula0');
4e445355 1952 $params = array_merge($params, $fullid_params);
1953 $where[] = "(d.forum $fullid_sql)";
42fb3c85 1954 }
42fb3c85 1955
6b7de0bb 1956 $selectdiscussion = "(".implode(" OR ", $where).")";
42fb3c85 1957
42fb3c85 1958 $messagesearch = '';
1959 $searchstring = '';
2b63df96 1960
42fb3c85 1961 // Need to concat these back together for parser to work.
1962 foreach($searchterms as $searchterm){
1963 if ($searchstring != '') {
1964 $searchstring .= ' ';
1965 }
1966 $searchstring .= $searchterm;
1967 }
1968
1969 // We need to allow quoted strings for the search. The quotes *should* be stripped
1970 // by the parser, but this should be examined carefully for security implications.
1971 $searchstring = str_replace("\\\"","\"",$searchstring);
1972 $parser = new search_parser();
1973 $lexer = new search_lexer($parser);
1974
1975 if ($lexer->parse($searchstring)) {
1976 $parsearray = $parser->get_parsed_array();
0a4ac01b 1977 // Experimental feature under 1.8! MDL-8830
1978 // Use alternative text searches if defined
1979 // This feature only works under mysql until properly implemented for other DBs
1980 // Requires manual creation of text index for forum_posts before enabling it:
1981 // CREATE FULLTEXT INDEX foru_post_tix ON [prefix]forum_posts (subject, message)
1982 // Experimental feature under 1.8! MDL-8830
532daab4 1983 if (!empty($CFG->forum_usetextsearches)) {
004efe66 1984 list($messagesearch, $msparams) = search_generate_text_SQL($parsearray, 'p.message', 'p.subject',
532daab4 1985 'p.userid', 'u.id', 'u.firstname',
1986 'u.lastname', 'p.modified', 'd.forum');
1987 } else {
004efe66 1988 list($messagesearch, $msparams) = search_generate_SQL($parsearray, 'p.message', 'p.subject',
532daab4 1989 'p.userid', 'u.id', 'u.firstname',
1990 'u.lastname', 'p.modified', 'd.forum');
1991 }
004efe66 1992 $params = array_merge($params, $msparams);
42fb3c85 1993 }
1994
4e445355 1995 $fromsql = "{forum_posts} p,
1996 {forum_discussions} d,
1997 {user} u";
42fb3c85 1998
1999 $selectsql = " $messagesearch
2000 AND p.discussion = d.id
2001 AND p.userid = u.id
2002 AND $selectdiscussion
2003 $extrasql";
2004
2005 $countsql = "SELECT COUNT(*)
2006 FROM $fromsql
2007 WHERE $selectsql";
2008
7f094149 2009 $searchsql = "SELECT p.*,
42fb3c85 2010 d.forum,
2011 u.firstname,
2012 u.lastname,
2013 u.email,
8ba59d07 2014 u.picture,
3a11c09f
PS
2015 u.imagealt,
2016 u.email
42fb3c85 2017 FROM $fromsql
2018 WHERE $selectsql
2019 ORDER BY p.modified DESC";
2020
4e445355 2021 $totalcount = $DB->count_records_sql($countsql, $params);
d50704bf 2022
4e445355 2023 return $DB->get_records_sql($searchsql, $params, $limitfrom, $limitnum);
42fb3c85 2024}
2025
0a4ac01b 2026/**
2027 * Returns a list of ratings for a particular post - sorted.
df1ba0f4 2028 *
2029 * @global object
2030 * @global object
90f4745c 2031 * @param int $postid
2032 * @param string $sort
df1ba0f4 2033 * @return array Array of ratings or false
0a4ac01b 2034 */
63e87951
AD
2035function forum_get_ratings($context, $postid, $sort="u.firstname ASC") {
2036 global $PAGE;
2037
2038 $options = new stdclass();
2039 $options->context = $PAGE->context;
2040 $options->itemid = $postid;
2041 $options->sort = "ORDER BY $sort";
2042
2043 get_all_ratings_for_item($options);
9fa49e22 2044}
2045
0a4ac01b 2046/**
2047 * Returns a list of all new posts that have not been mailed yet
df1ba0f4 2048 *
2049 * @global object
2050 * @global object
2051 * @param int $starttime posts created after this time
2052 * @param int $endtime posts created before this
2053 * @param int $now used for timed discussions only
2054 * @return array
0a4ac01b 2055 */
90f4745c 2056function forum_get_unmailed_posts($starttime, $endtime, $now=null) {
4e445355 2057 global $CFG, $DB;
90f4745c 2058
4e445355 2059 $params = array($starttime, $endtime);
90f4745c 2060 if (!empty($CFG->forum_enabletimedposts)) {
2061 if (empty($now)) {
2062 $now = time();
2063 }
4e445355 2064 $timedsql = "AND (d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?))";
2065 $params[] = $now;
2066 $params[] = $now;
90f4745c 2067 } else {
2068 $timedsql = "";
2069 }
2070
4e445355 2071 return $DB->get_records_sql("SELECT p.*, d.course, d.forum
2072 FROM {forum_posts} p
2073 JOIN {forum_discussions} d ON d.id = p.discussion
65b0e537 2074 WHERE p.mailed = 0
4e445355 2075 AND p.created >= ?
2076 AND (p.created < ? OR p.mailnow = 1)
90f4745c 2077 $timedsql
4e445355 2078 ORDER BY p.modified ASC", $params);
1f48942e 2079}
2080
0a4ac01b 2081/**
2082 * Marks posts before a certain time as being mailed already
df1ba0f4 2083 *
2084 * @global object
2085 * @global object
2086 * @param int $endtime
2087 * @param int $now Defaults to time()
2088 * @return bool
0a4ac01b 2089 */
90f4745c 2090function forum_mark_old_posts_as_mailed($endtime, $now=null) {
4e445355 2091 global $CFG, $DB;
90f4745c 2092 if (empty($now)) {
2093 $now = time();
2094 }
2095
2096 if (empty($CFG->forum_enabletimedposts)) {
4e445355 2097 return $DB->execute("UPDATE {forum_posts}
90f4745c 2098 SET mailed = '1'
4e445355 2099 WHERE (created < ? OR mailnow = 1)
3342790c 2100 AND mailed = 0", array($endtime));
90f4745c 2101
0f620d4b 2102 } else {
4e445355 2103 return $DB->execute("UPDATE {forum_posts}
90f4745c 2104 SET mailed = '1'
2105 WHERE discussion NOT IN (SELECT d.id
4e445355 2106 FROM {forum_discussions} d
2107 WHERE d.timestart > ?)
2108 AND (created < ? OR mailnow = 1)
3342790c 2109 AND mailed = 0", array($now, $endtime));
0f620d4b 2110 }
3ecca1ee 2111}
2112
0a4ac01b 2113/**
2114 * Get all the posts for a user in a forum suitable for forum_print_post
df1ba0f4 2115 *
2116 * @global object
2117 * @global object
2118 * @uses CONTEXT_MODULE
2119 * @return array
0a4ac01b 2120 */
1f48942e 2121function forum_get_user_posts($forumid, $userid) {
4e445355 2122 global $CFG, $DB;
1f48942e 2123
90f4745c 2124 $timedsql = "";
4e445355 2125 $params = array($forumid, $userid);
2126
90f4745c 2127 if (!empty($CFG->forum_enabletimedposts)) {
2128 $cm = get_coursemodule_from_instance('forum', $forumid);
2129 if (!has_capability('mod/forum:viewhiddentimedposts' , get_context_instance(CONTEXT_MODULE, $cm->id))) {
2130 $now = time();
4e445355 2131 $timedsql = "AND (d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?))";
2132 $params[] = $now;
2133 $params[] = $now;
6b7de0bb 2134 }
90f4745c 2135 }
2136
4e445355 2137 return $DB->get_records_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture, u.imagealt
2138 FROM {forum} f
2139 JOIN {forum_discussions} d ON d.forum = f.id
2140 JOIN {forum_posts} p ON p.discussion = d.id
2141 JOIN {user} u ON u.id = p.userid
2142 WHERE f.id = ?
2143 AND p.userid = ?
90f4745c 2144 $timedsql
4e445355 2145 ORDER BY p.modified ASC", $params);
1f48942e 2146}
2147
90f4745c 2148/**
2149 * Get all the discussions user participated in
df1ba0f4 2150 *
2151 * @global object
2152 * @global object
2153 * @uses CONTEXT_MODULE
90f4745c 2154 * @param int $forumid
2155 * @param int $userid
df1ba0f4 2156 * @return array Array or false
90f4745c 2157 */
2158function forum_get_user_involved_discussions($forumid, $userid) {
4e445355 2159 global $CFG, $DB;
90f4745c 2160
2161 $timedsql = "";
4e445355 2162 $params = array($forumid, $userid);
90f4745c 2163 if (!empty($CFG->forum_enabletimedposts)) {
2164 $cm = get_coursemodule_from_instance('forum', $forumid);
2165 if (!has_capability('mod/forum:viewhiddentimedposts' , get_context_instance(CONTEXT_MODULE, $cm->id))) {
2166 $now = time();
4e445355 2167 $timedsql = "AND (d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?))";
2168 $params[] = $now;
2169 $params[] = $now;
6b7de0bb 2170 }
90f4745c 2171 }
2172
4e445355 2173 return $DB->get_records_sql("SELECT DISTINCT d.*
2174 FROM {forum} f
2175 JOIN {forum_discussions} d ON d.forum = f.id
2176 JOIN {forum_posts} p ON p.discussion = d.id
2177 WHERE f.id = ?
2178 AND p.userid = ?
2179 $timedsql", $params);
90f4745c 2180}
2181
2182/**
2183 * Get all the posts for a user in a forum suitable for forum_print_post
df1ba0f4 2184 *
2185 * @global object
2186 * @global object
90f4745c 2187 * @param int $forumid
2188 * @param int $userid
2189 * @return array of counts or false
2190 */
2191function forum_count_user_posts($forumid, $userid) {
4e445355 2192 global $CFG, $DB;
90f4745c 2193
2194 $timedsql = "";
4e445355 2195 $params = array($forumid, $userid);
90f4745c 2196 if (!empty($CFG->forum_enabletimedposts)) {
2197 $cm = get_coursemodule_from_instance('forum', $forumid);
2198 if (!has_capability('mod/forum:viewhiddentimedposts' , get_context_instance(CONTEXT_MODULE, $cm->id))) {
2199 $now = time();
4e445355 2200 $timedsql = "AND (d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?))";
2201 $params[] = $now;
2202 $params[] = $now;
6b7de0bb 2203 }
90f4745c 2204 }
2205
4e445355 2206 return $DB->get_record_sql("SELECT COUNT(p.id) AS postcount, MAX(p.modified) AS lastpost
2207 FROM {forum} f
2208 JOIN {forum_discussions} d ON d.forum = f.id
2209 JOIN {forum_posts} p ON p.discussion = d.id
2210 JOIN {user} u ON u.id = p.userid
2211 WHERE f.id = ?
2212 AND p.userid = ?
2213 $timedsql", $params);
90f4745c 2214}
2215
0a4ac01b 2216/**
2217 * Given a log entry, return the forum post details for it.
df1ba0f4 2218 *
2219 * @global object
2220 * @global object
2221 * @param object $log
2222 * @return array|null
0a4ac01b 2223 */
1f48942e 2224function forum_get_post_from_log($log) {
4e445355 2225 global $CFG, $DB;
1f48942e 2226
2227 if ($log->action == "add post") {
2228
4e445355 2229 return $DB->get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
8f7dc7f1 2230 u.firstname, u.lastname, u.email, u.picture
4e445355 2231 FROM {forum_discussions} d,
2232 {forum_posts} p,
2233 {forum} f,
2234 {user} u
2235 WHERE p.id = ?
65b0e537 2236 AND d.id = p.discussion
2237 AND p.userid = u.id
8f7dc7f1 2238 AND u.deleted <> '1'
4e445355 2239 AND f.id = d.forum", array($log->info));
1f48942e 2240
2241
2242 } else if ($log->action == "add discussion") {
2243
4e445355 2244 return $DB->get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
8f7dc7f1 2245 u.firstname, u.lastname, u.email, u.picture
4e445355 2246 FROM {forum_discussions} d,
2247 {forum_posts} p,
2248 {forum} f,
2249 {user} u
2250 WHERE d.id = ?
65b0e537 2251 AND d.firstpost = p.id
2252 AND p.userid = u.id
8f7dc7f1 2253 AND u.deleted <> '1'
4e445355 2254 AND f.id = d.forum", array($log->info));
1f48942e 2255 }
2256 return NULL;
2257}
2258
0a4ac01b 2259/**
2260 * Given a discussion id, return the first post from the discussion
df1ba0f4 2261 *
2262 * @global object
2263 * @global object
2264 * @param int $dicsussionid
2265 * @return array
0a4ac01b 2266 */
d05956ac 2267function forum_get_firstpost_from_discussion($discussionid) {
4e445355 2268 global $CFG, $DB;
d05956ac 2269
4e445355 2270 return $DB->get_record_sql("SELECT p.*
2271 FROM {forum_discussions} d,
2272 {forum_posts} p
2273 WHERE d.id = ?
2274 AND d.firstpost = p.id ", array($discussionid));
d05956ac 2275}
2276
0a4ac01b 2277/**
90f4745c 2278 * Returns an array of counts of replies to each discussion
df1ba0f4 2279 *
2280 * @global object
2281 * @global object
2282 * @param int $forumid
2283 * @param string $forumsort
2284 * @param int $limit
2285 * @param int $page
2286 * @param int $perpage
2287 * @return array
0a4ac01b 2288 */
90f4745c 2289function forum_count_discussion_replies($forumid, $forumsort="", $limit=-1, $page=-1, $perpage=0) {
4e445355 2290 global $CFG, $DB;
1f48942e 2291
90f4745c 2292 if ($limit > 0) {
2293 $limitfrom = 0;
2294 $limitnum = $limit;
2295 } else if ($page != -1) {
2296 $limitfrom = $page*$perpage;
2297 $limitnum = $perpage;
2298 } else {
2299 $limitfrom = 0;
2300 $limitnum = 0;
2301 }
2302
2303 if ($forumsort == "") {
2304 $orderby = "";
2305 $groupby = "";
2306
2307 } else {
2308 $orderby = "ORDER BY $forumsort";
2309 $groupby = ", ".strtolower($forumsort);
2310 $groupby = str_replace('desc', '', $groupby);
2311 $groupby = str_replace('asc', '', $groupby);
2312 }
2313
bfeb10b7 2314 if (($limitfrom == 0 and $limitnum == 0) or $forumsort == "") {
2315 $sql = "SELECT p.discussion, COUNT(p.id) AS replies, MAX(p.id) AS lastpostid
4e445355 2316 FROM {forum_posts} p
2317 JOIN {forum_discussions} d ON p.discussion = d.id
2318 WHERE p.parent > 0 AND d.forum = ?
bfeb10b7 2319 GROUP BY p.discussion";
4e445355 2320 return $DB->get_records_sql($sql, array($forumid));
bfeb10b7 2321
90f4745c 2322 } else {
bfeb10b7 2323 $sql = "SELECT p.discussion, (COUNT(p.id) - 1) AS replies, MAX(p.id) AS lastpostid
4e445355 2324 FROM {forum_posts} p
2325 JOIN {forum_discussions} d ON p.discussion = d.id
2326 WHERE d.forum = ?
bfeb10b7 2327 GROUP BY p.discussion $groupby
2328 $orderby";
4e445355 2329 return $DB->get_records_sql("SELECT * FROM ($sql) sq", array($forumid), $limitfrom, $limitnum);
90f4745c 2330 }
2331}
2332
df1ba0f4 2333/**
2334 * @global object
2335 * @global object
2336 * @global object
2337 * @staticvar array $cache
2338 * @param object $forum
2339 * @param object $cm
2340 * @param object $course
2341 * @return mixed
2342 */
90f4745c 2343function forum_count_discussions($forum, $cm, $course) {
4e445355 2344 global $CFG, $DB, $USER;
90f4745c 2345
2346 static $cache = array();
2347
2348 $now = round(time(), -2); // db cache friendliness
2349
4e445355 2350 $params = array($course->id);
2351
90f4745c 2352 if (!isset($cache[$course->id])) {
2353 if (!empty($CFG->forum_enabletimedposts)) {
4e445355 2354 $timedsql = "AND d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?)";
2355 $params[] = $now;
2356 $params[] = $now;
90f4745c 2357 } else {
2358 $timedsql = "";
2359 }
2360
2361 $sql = "SELECT f.id, COUNT(d.id) as dcount
4e445355 2362 FROM {forum} f
2363 JOIN {forum_discussions} d ON d.forum = f.id
2364 WHERE f.course = ?
90f4745c 2365 $timedsql
2366 GROUP BY f.id";
a48e8c4b 2367
4e445355 2368 if ($counts = $DB->get_records_sql($sql, $params)) {
90f4745c 2369 foreach ($counts as $count) {
2370 $counts[$count->id] = $count->dcount;
2371 }
2372 $cache[$course->id] = $counts;
2373 } else {
2374 $cache[$course->id] = array();
2375 }
a48e8c4b 2376 }
90f4745c 2377
2378 if (empty($cache[$course->id][$forum->id])) {
2379 return 0;
a48e8c4b 2380 }
90f4745c 2381
2382 $groupmode = groups_get_activity_groupmode($cm, $course);
2383
2384 if ($groupmode != SEPARATEGROUPS) {
2385 return $cache[$course->id][$forum->id];
1f48942e 2386 }
90f4745c 2387
948091f4 2388 if (has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) {
90f4745c 2389 return $cache[$course->id][$forum->id];
2390 }
2391
2392 require_once($CFG->dirroot.'/course/lib.php');
2393
2394 $modinfo =& get_fast_modinfo($course);
2395 if (is_null($modinfo->groups)) {
2396 $modinfo->groups = groups_get_user_groups($course->id, $USER->id);
2397 }
2398
98da6021
PS
2399 if (array_key_exists($cm->groupingid, $modinfo->groups)) {
2400 $mygroups = $modinfo->groups[$cm->groupingid];
90f4745c 2401 } else {
98da6021 2402 $mygroups = false; // Will be set below
90f4745c 2403 }
2404
2405 // add all groups posts
2406 if (empty($mygroups)) {
2407 $mygroups = array(-1=>-1);
2408 } else {
2409 $mygroups[-1] = -1;
2410 }
4e445355 2411
2412 list($mygroups_sql, $params) = $DB->get_in_or_equal($mygroups);
2413 $params[] = $forum->id;
90f4745c 2414
2415 if (!empty($CFG->forum_enabletimedposts)) {
2416 $timedsql = "AND d.timestart < $now AND (d.timeend = 0 OR d.timeend > $now)";
4e445355 2417 $params[] = $now;
2418 $params[] = $now;
90f4745c 2419 } else {
2420 $timedsql = "";
2421 }
2422
2423 $sql = "SELECT COUNT(d.id)
4e445355 2424 FROM {forum_discussions} d
342650a7 2425 WHERE d.groupid $mygroups_sql AND d.forum = ?
90f4745c 2426 $timedsql";
2427
4e445355 2428 return $DB->get_field_sql($sql, $params);
1f48942e 2429}
2430
0a4ac01b 2431/**
63e87951 2432 * How many posts by other users are unrated by a given user in the given discussion?
df1ba0f4 2433 *
2434 * @global object
2435 * @global object
2436 * @param int $discussionid
2437 * @param int $userid
2438 * @return mixed
0a4ac01b 2439 */
1f48942e 2440function forum_count_unrated_posts($discussionid, $userid) {
4e445355 2441 global $CFG, $DB;
2442 if ($posts = $DB->get_record_sql("SELECT count(*) as num
2443 FROM {forum_posts}
65b0e537 2444 WHERE parent > 0
4e445355 2445 AND discussion = ?
2446 AND userid <> ? ", array($discussionid, $userid))) {
1f48942e 2447
4e445355 2448 if ($rated = $DB->get_record_sql("SELECT count(*) as num
2449 FROM {forum_posts} p,
63e87951 2450 {rating} r
4e445355 2451 WHERE p.discussion = ?
63e87951 2452 AND p.id = r.itemid
4e445355 2453 AND r.userid = ?", array($discussionid, $userid))) {
1f48942e 2454 $difference = $posts->num - $rated->num;
2455 if ($difference > 0) {
2456 return $difference;
2457 } else {
2458 return 0; // Just in case there was a counting error
2459 }
2460 } else {
2461 return $posts->num;
2462 }
2463 } else {
2464 return 0;
2465 }
2466}
2467
0a4ac01b 2468/**
2469 * Get all discussions in a forum
df1ba0f4 2470 *
2471 * @global object
2472 * @global object
2473 * @global object
2474 * @uses CONTEXT_MODULE
2475 * @uses VISIBLEGROUPS
2476 * @param object $cm
2477 * @param string $forumsort
2478 * @param bool $fullpost
2479 * @param int $unused
2480 * @param int $limit
2481 * @param bool $userlastmodified
2482 * @param int $page
2483 * @param int $perpage
2484 * @return array
0a4ac01b 2485 */
90f4745c 2486function forum_get_discussions($cm, $forumsort="d.timemodified DESC", $fullpost=true, $unused=-1, $limit=-1, $userlastmodified=false, $page=-1, $perpage=0) {
4e445355 2487 global $CFG, $DB, $USER;
0fcac008 2488
3d284127 2489 $timelimit = '';
2490
90f4745c 2491 $now = round(time(), -2);
4e445355 2492 $params = array($cm->instance);
90f4745c 2493
4436a63b 2494 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2b63df96 2495
4436a63b 2496 if (!has_capability('mod/forum:viewdiscussion', $modcontext)) { /// User must have perms to view discussions
2497 return array();
2498 }
2499
2500 if (!empty($CFG->forum_enabletimedposts)) { /// Users must fulfill timed posts
2b63df96 2501
0468976c 2502 if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
4e445355 2503 $timelimit = " AND ((d.timestart <= ? AND (d.timeend = 0 OR d.timeend > ?))";
2504 $params[] = $now;
2505 $params[] = $now;
90f4745c 2506 if (isloggedin()) {
4e445355 2507 $timelimit .= " OR d.userid = ?";
2508 $params[] = $USER->id;
3d284127 2509 }
90f4745c 2510 $timelimit .= ")";
fbc21e82 2511 }
fbc21e82 2512 }
1f48942e 2513
90f4745c 2514 if ($limit > 0) {
2515 $limitfrom = 0;
2516 $limitnum = $limit;
2517 } else if ($page != -1) {
2518 $limitfrom = $page*$perpage;
2519 $limitnum = $perpage;
2520 } else {
2521 $limitfrom = 0;
2522 $limitnum = 0;
90ec387a 2523 }
8f0cd6ef 2524
90f4745c 2525 $groupmode = groups_get_activity_groupmode($cm);
2526 $currentgroup = groups_get_activity_group($cm);
353228d8 2527
fffa8b35 2528 if ($groupmode) {
2529 if (empty($modcontext)) {
2530 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2531 }
2532
2533 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
2534 if ($currentgroup) {
4e445355 2535 $groupselect = "AND (d.groupid = ? OR d.groupid = -1)";
2536 $params[] = $currentgroup;
fffa8b35 2537 } else {
2538 $groupselect = "";
2539 }
2540
2541 } else {
2542 //seprate groups without access all
2543 if ($currentgroup) {
4e445355 2544 $groupselect = "AND (d.groupid = ? OR d.groupid = -1)";
2545 $params[] = $currentgroup;
fffa8b35 2546 } else {
2547 $groupselect = "AND d.groupid = -1";
2548 }
2549 }
353228d8 2550 } else {
02509fe6 2551 $groupselect = "";
2552 }
2862b309 2553
fffa8b35 2554
29507631 2555 if (empty($forumsort)) {
2556 $forumsort = "d.timemodified DESC";
2557 }
2ab968e9 2558 if (empty($fullpost)) {
b879effb 2559 $postdata = "p.id,p.subject,p.modified,p.discussion,p.userid";
2ab968e9 2560 } else {
2561 $postdata = "p.*";
2562 }
9197e147 2563
13597d01 2564 if (empty($userlastmodified)) { // We don't need to know this
fffa8b35 2565 $umfields = "";
2566 $umtable = "";
13597d01 2567 } else {
fffa8b35 2568 $umfields = ", um.firstname AS umfirstname, um.lastname AS umlastname";
4e445355 2569 $umtable = " LEFT JOIN {user} um ON (d.usermodified = um.id)";
90f4745c 2570 }
2571
2572 $sql = "SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid, d.timestart, d.timeend,
2573 u.firstname, u.lastname, u.email, u.picture, u.imagealt $umfields
4e445355 2574 FROM {forum_discussions} d
2575 JOIN {forum_posts} p ON p.discussion = d.id
2576 JOIN {user} u ON p.userid = u.id
90f4745c 2577 $umtable
4e445355 2578 WHERE d.forum = ? AND p.parent = 0
90f4745c 2579 $timelimit $groupselect
2580 ORDER BY $forumsort";
4e445355 2581 return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
90f4745c 2582}
2583
df1ba0f4 2584/**
2585 *
2586 * @global object
2587 * @global object
2588 * @global object
2589 * @uses CONTEXT_MODULE
2590 * @uses VISIBLEGROUPS
2591 * @param object $cm
2592 * @return array
2593 */
bfeb10b7 2594function forum_get_discussions_unread($cm) {
4e445355 2595 global $CFG, $DB, $USER;
90f4745c 2596
2597 $now = round(time(), -2);
4e445355 2598 $params = array($cutoffdate);
90f4745c 2599 $groupmode = groups_get_activity_groupmode($cm);
2600 $currentgroup = groups_get_activity_group($cm);
2601
2602 if ($groupmode) {
2603 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2604
2605 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
2606 if ($currentgroup) {
4e445355 2607 $groupselect = "AND (d.groupid = ? OR d.groupid = -1)";
2608 $params[] = $currentgroup;
90f4745c 2609 } else {
2610 $groupselect = "";
2611 }
2612
2613 } else {
2614 //seprate groups without access all
2615 if ($currentgroup) {
4e445355 2616 $groupselect = "AND (d.groupid = ? OR d.groupid = -1)";
2617 $params[] = $currentgroup;
90f4745c 2618 } else {
2619 $groupselect = "AND d.groupid = -1";
2620 }
2621 }
2622 } else {
2623 $groupselect = "";
13597d01 2624 }
2625
90f4745c 2626 $cutoffdate = $now - ($CFG->forum_oldpostdays*24*60*60);
2627
2628 if (!empty($CFG->forum_enabletimedposts)) {
4e445355 2629 $timedsql = "AND d.timestart < ? AND (d.timeend = 0 OR d.timeend > ?)";
2630 $params[] = $now;
2631 $params[] = $now;
90f4745c 2632 } else {
2633 $timedsql = "";
2634 }
2635
2636 $sql = "SELECT d.id, COUNT(p.id) AS unread
4e445355 2637 FROM {forum_discussions} d
2638 JOIN {forum_posts} p ON p.discussion = d.id
2639 LEFT JOIN {forum_read} r ON (r.postid = p.id AND r.userid = $USER->id)
90f4745c 2640 WHERE d.forum = {$cm->instance}
4e445355 2641 AND p.modified >= ? AND r.id is NULL
90f4745c 2642 $groupselect
4e445355 2643 $timedsql
bfeb10b7 2644 GROUP BY d.id";
4e445355 2645 if ($unreads = $DB->get_records_sql($sql, $params)) {
90f4745c 2646 foreach ($unreads as $unread) {
2647 $unreads[$unread->id] = $unread->unread;
2648 }
2649 return $unreads;
2650 } else {
2651 return array();
2652 }
1f48942e 2653}
2654
df1ba0f4 2655/**
2656 * @global object
2657 * @global object
2658 * @global object
2659 * @uses CONEXT_MODULE
2660 * @uses VISIBLEGROUPS
2661 * @param object $cm
2662 * @return array
2663 */
90f4745c 2664function forum_get_discussions_count($cm) {
4e445355 2665 global $CFG, $DB, $USER;
90f4745c 2666
2667 $now = round(time(), -2);
4e445355 2668 $params = array($cm->instance);
90f4745c 2669 $groupmode = groups_get_activity_groupmode($cm);
2670 $currentgroup = groups_get_activity_group($cm);
2671
2672 if ($groupmode) {
2673 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2674
2675 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
2676 if ($currentgroup) {
4e445355 2677 $groupselect = "AND (d.groupid = ? OR d.groupid = -1)";
2678 $params[] = $currentgroup;
90f4745c 2679 } else {
2680 $groupselect = "";
2681 }
2682
2683 } else {
2684 //seprate groups without access all
2685 if ($currentgroup) {
4e445355 2686 $groupselect = "AND (d.groupid = ? OR d.groupid = -1)";
2687 $params[] = $currentgroup;
90f4745c 2688 } else {
2689 $groupselect = "AND d.groupid = -1";
2690 }
2691 }
2692 } else {
2693 $groupselect = "";
2694 }
2695
2696 $cutoffdate = $now - ($CFG->forum_oldpostdays*24*60*60);
2697
2698 $timelimit = "";
2699
2700 if (!empty($CFG->forum_enabletimedposts)) {
2701
2702 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2703
2704 if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
4e445355 2705 $timelimit = " AND ((d.timestart <= ? AND (d.timeend = 0 OR d.timeend > ?))";
2706 $params[] = $now;
2707 $params[] = $now;
90f4745c 2708 if (isloggedin()) {
4e445355 2709 $timelimit .= " OR d.userid = ?";
2710 $params[] = $USER->id;
90f4745c 2711 }
2712 $timelimit .= ")";
2713 }
2714 }
2715
2716 $sql = "SELECT COUNT(d.id)
4e445355 2717 FROM {forum_discussions} d
2718 JOIN {forum_posts} p ON p.discussion = d.id
2719 WHERE d.forum = ? AND p.parent = 0
2720 $groupselect $timelimit";
90f4745c 2721
4e445355 2722 return $DB->get_field_sql($sql, $params);
90f4745c 2723}
1f48942e 2724
2725
0a4ac01b 2726/**
2727 * Get all discussions started by a particular user in a course (or group)
2728 * This function no longer used ...
df1ba0f4 2729 *
2730 * @todo Remove this function if no longer used
2731 * @global object
2732 * @global object
2733 * @param int $courseid
2734 * @param int $userid
2735 * @param int $groupid
2736 * @return array
0a4ac01b 2737 */
b656e2a9 2738function forum_get_user_discussions($courseid, $userid, $groupid=0) {
4e445355 2739 global $CFG, $DB;
2740 $params = array($courseid, $userid);
b656e2a9 2741 if ($groupid) {
4e445355 2742 $groupselect = " AND d.groupid = ? ";
2743 $params[] = $groupid;
b656e2a9 2744 } else {
2745 $groupselect = "";
2746 }
2747
4e445355 2748 return $DB->get_records_sql("SELECT p.*, d.groupid, u.firstname, u.lastname, u.email, u.picture, u.imagealt,
ebc3bd2b 2749 f.type as forumtype, f.name as forumname, f.id as forumid
4e445355 2750 FROM {forum_discussions} d,
2751 {forum_posts} p,
2752 {user} u,
2753 {forum} f
2754 WHERE d.course = ?
65b0e537 2755 AND p.discussion = d.id
2756 AND p.parent = 0
2757 AND p.userid = u.id
4e445355 2758 AND u.id = ?
b656e2a9 2759 AND d.forum = f.id $groupselect
4e445355 2760 ORDER BY p.created DESC", $params);
1f48942e 2761}
2762
0a4ac01b 2763/**
702dc57b 2764 * Get the list of potential subscribers to a forum.
8d8d0bfa 2765 *
2766 * @param object $forumcontext the forum context.
2767 * @param integer $groupid the id of a group, or 0 for all groups.
2768 * @param string $fields the list of fields to return for each user. As for get_users_by_capability.
2769 * @param string $sort sort order. As for get_users_by_capability.
2770 * @return array list of users.
0a4ac01b 2771 */
8d8d0bfa 2772function forum_get_potential_subscribers($forumcontext, $groupid, $fields, $sort) {
2773 return get_users_by_capability($forumcontext, 'mod/forum:initialsubscriptions', $fields, $sort, '', '', $groupid, '', false, true);
2774}
0a4ac01b 2775
8d8d0bfa 2776/**
2777 * Returns list of user objects that are subscribed to this forum
2778 *
df1ba0f4 2779 * @global object
2780 * @global object
8d8d0bfa 2781 * @param object $course the course
2782 * @param forum $forum the forum
2783 * @param integer $groupid group id, or 0 for all.
2784 * @param object $context the forum context, to save re-fetching it where possible.
2785 * @return array list of users.
2786 */
2787function forum_subscribed_users($course, $forum, $groupid=0, $context = NULL) {
4e445355 2788 global $CFG, $DB;
2789 $params = array($forum->id);
1f48942e 2790
6673d7bd 2791 if ($groupid) {
4e445355 2792 $grouptables = ", {groups_members} gm ";
2793 $groupselect = "AND gm.groupid = ? AND u.id = gm.userid";
2794 $params[] = $groupid;
6673d7bd 2795 } else {
669f2499 2796 $grouptables = '';
2797 $groupselect = '';
6673d7bd 2798 }
2799
4e445355 2800 $fields ="u.id,
2801 u.username,
2802 u.firstname,
2803 u.lastname,
2804 u.maildisplay,
2805 u.mailformat,
2806 u.maildigest,
2807 u.emailstop,
2808 u.imagealt,
2809 u.email,
2810 u.city,
2811 u.country,
2812 u.lastaccess,
2813 u.lastlogin,
2814 u.picture,
2815 u.timezone,
2816 u.theme,
2817 u.lang,
2818 u.trackforums,
2819 u.mnethostid";
2820
a9900c73 2821 if (forum_is_forcesubscribed($forum)) {
48dcaf58 2822 if (empty($context)) {
2823 $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id);
2824 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
8d8d0bfa 2825 }
c37fdcb5 2826 $sort = "u.email ASC";
8d8d0bfa 2827 $results = forum_get_potential_subscribers($context, $groupid, $fields, $sort);
669f2499 2828 } else {
4e445355 2829 $results = $DB->get_records_sql("SELECT $fields
2830 FROM {user} u,
2831 {forum_subscriptions} s $grouptables
2832 WHERE s.forum = ?
65b0e537 2833 AND s.userid = u.id
df1c2c71 2834 AND u.deleted = 0 $groupselect
4e445355 2835 ORDER BY u.email ASC", $params);
669f2499 2836 }
2837
df1c2c71 2838 static $guestid = null;
2839
2840 if (is_null($guestid)) {
2841 if ($guest = guest_user()) {
2842 $guestid = $guest->id;
2843 } else {
2844 $guestid = 0;
2845 }
669f2499 2846 }
2847
df1c2c71 2848 // Guest user should never be subscribed to a forum.
2849 unset($results[$guestid]);
2850
669f2499 2851 return $results;
1f48942e 2852}
9fa49e22 2853
067675c0 2854
2855
0a4ac01b 2856// OTHER FUNCTIONS ///////////////////////////////////////////////////////////
f93f848a 2857
2858
df1ba0f4 2859/**
2860 * @global object
2861 * @global object
2862 * @param int $courseid
2863 * @param string $type
2864 */
11b0c469 2865function forum_get_course_forum($courseid, $type) {
2866// How to set up special 1-per-course forums
9146b979 2867 global $CFG, $DB, $OUTPUT;
a6fcdf98 2868
4e445355 2869 if ($forums = $DB->get_records_select("forum", "course = ? AND type = ?", array($courseid, $type), "id ASC")) {
65b0e537 2870 // There should always only be ONE, but with the right combination of
29cbd93a 2871 // errors there might be more. In this case, just return the oldest one (lowest ID).
2872 foreach ($forums as $forum) {
2873 return $forum; // ie the first one
11b0c469 2874 }
8daaf761 2875 }
e6874d9f 2876
8daaf761 2877 // Doesn't exist, so create one now.
2878 $forum->course = $courseid;
2879 $forum->type = "$type";
2880 switch ($forum->type) {
2881 case "news":
294ce987 2882 $forum->name = get_string("namenews", "forum");
2883 $forum->intro = get_string("intronews", "forum");
906fef94 2884 $forum->forcesubscribe = FORUM_FORCESUBSCRIBE;
8daaf761 2885 $forum->assessed = 0;
709f0ec8 2886 if ($courseid == SITEID) {
2887 $forum->name = get_string("sitenews");
2888 $forum->forcesubscribe = 0;
8f0cd6ef 2889 }
8daaf761 2890 break;
2891 case "social":
294ce987 2892 $forum->name = get_string("namesocial", "forum");
2893 $forum->intro = get_string("introsocial", "forum");
8daaf761 2894 $forum->assessed = 0;
2895 $forum->forcesubscribe = 0;
2896 break;
1c7b8b93
NC
2897 case "blog":
2898 $forum->name = get_string('blogforum', 'forum');
2899 $forum->intro = get_string('introblog', 'forum');
2900 $forum->assessed = 0;
2901 $forum->forcesubscribe = 0;
2902 break;
8daaf761 2903 default:
9146b979 2904 echo $OUTPUT->notification("That forum type doesn't exist!");
8daaf761 2905 return false;
2906 break;
2907 }
2908
2909 $forum->timemodified = time();
4e445355 2910 $forum->id = $DB->insert_record("forum", $forum);
8daaf761 2911
4e445355 2912 if (! $module = $DB->get_record("modules", array("name" => "forum"))) {
9146b979 2913 echo $OUTPUT->notification("Could not find forum module!!");
e1b5643f 2914 return false;
82aa0e8d 2915 }
0b5a80a1 2916 $mod = new object();
e1b5643f 2917 $mod->course = $courseid;
2918 $mod->module = $module->id;
2919 $mod->instance = $forum->id;
2920 $mod->section = 0;
2921 if (! $mod->coursemodule = add_course_module($mod) ) { // assumes course/lib.php is loaded
9146b979 2922 echo $OUTPUT->notification("Could not add a new course module to the course '" . format_string($course->fullname) . "'");
e1b5643f 2923 return false;
2924 }
2925 if (! $sectionid = add_mod_to_section($mod) ) { // assumes course/lib.php is loaded
9146b979 2926 echo $OUTPUT->notification("Could not add the new course module to that section");
e1b5643f 2927 return false;
2928 }
4e445355 2929 if (! $DB->set_field("course_modules", "section", $sectionid, array("id" => $mod->coursemodule))) {
9146b979 2930 echo $OUTPUT->notification("Could not update the course module with the correct section");
e1b5643f 2931 return false;
2932 }
2933 include_once("$CFG->dirroot/course/lib.php");
2934 rebuild_course_cache($courseid);
65b0e537 2935
4e445355 2936 return $DB->get_record("forum", array("id" => "$forum->id"));
82aa0e8d 2937}
2938
f93f848a 2939
0a4ac01b 2940/**
df1ba0f4 2941 * Given the data about a posting, builds up the HTML to display it and
2942 * returns the HTML in a string. This is designed for sending via HTML email.
2943 *
2944 * @global object
2945 * @param object $course
2946 * @param object $cm
2947 * @param object $forum
2948 * @param object $discussion
2949 * @param object $post
2950 * @param object $userform
2951 * @param object $userto
2952 * @param bool $ownpost
2953 * @param bool $reply
2954 * @param bool $link
2955 * @param bool $rate
2956 * @param string $footer
2957 * @return string
2958 */
0faf6791 2959function forum_make_mail_post($course, $cm, $forum, $discussion, $post, $userfrom, $userto,
11b0c469 2960 $ownpost=false, $reply=false, $link=false, $rate=false, $footer="") {
2b63df96 2961
59e28d8f 2962 global $CFG, $OUTPUT;
501cdbd8 2963
df1c2c71 2964 if (!isset($userto->viewfullnames[$forum->id])) {
2965 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
12e57b92 2966 print_error('invalidcoursemodule');
df1c2c71 2967 }
2968 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2969 $viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext, $userto->id);
2970 } else {
2971 $viewfullnames = $userto->viewfullnames[$forum->id];
7613e6d7 2972 }
7613e6d7 2973
1306c5ea 2974 // format the post body
2975 $options = new object();
2976 $options->para = true;
e2d7687f 2977 $formattedtext = format_text($post->message, $post->messageformat, $options, $course->id);
0d851f90 2978
add3201e 2979 $output = '<table border="0" cellpadding="3" cellspacing="0" class="forumpost">';
501cdbd8 2980
add3201e 2981 $output .= '<tr class="header"><td width="35" valign="top" class="picture left">';
812dbaf7 2982 $output .= $OUTPUT->user_picture($userfrom, array('courseid'=>$course->id));
add3201e 2983 $output .= '</td>';
501cdbd8 2984
2985 if ($post->parent) {
add3201e 2986 $output .= '<td class="topic">';
501cdbd8 2987 } else {
add3201e 2988 $output .= '<td class="topic starter">';
501cdbd8 2989 }
add3201e 2990 $output .= '<div class="subject">'.format_string($post->subject).'</div>';
1b26d5e7 2991
df1c2c71 2992 $fullname = fullname($userfrom, $viewfullnames);
1306c5ea 2993 $by = new object();
df1c2c71 2994 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userfrom->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
2995 $by->date = userdate($post->modified, '', $userto->timezone);
add3201e 2996 $output .= '<div class="author">'.get_string('bynameondate', 'forum', $by).'</div>';
2997
2998 $output .= '</td></tr>';
2999
7b54f563 3000 $output .= '<tr><td class="left side" valign="top">';
df1c2c71 3001
3002 if (isset($userfrom->groups)) {
3003 $groups = $userfrom->groups[$forum->id];
3004 } else {
3005 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
12e57b92 3006 print_error('invalidcoursemodule');
df1c2c71 3007 }
3008 $group = groups_get_all_groups($course->id, $userfrom->id, $cm->groupingid);
3009 }
3010
3011 if ($groups) {
3012 $output .= print_group_picture($groups, $course->id, false, true, true);
add3201e 3013 } else {
3014 $output .= '&nbsp;';
3015 }
1b26d5e7 3016
add3201e 3017 $output .= '</td><td class="content">';
501cdbd8 3018
0faf6791 3019 $attachments = forum_print_attachments($post, $cm, 'html');
3020 if ($attachments !== '') {
add3201e 3021 $output .= '<div class="attachments">';
0faf6791 3022 $output .= $attachments;
3023 $output .= '</div>';
7f6689e4 3024 }
3025
0d851f90 3026 $output .= $formattedtext;
501cdbd8 3027
0a4ac01b 3028// Commands
add3201e 3029 $commands = array();
501cdbd8 3030
2e2e71a8 3031 if ($post->parent) {
add3201e 3032 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
3033 $post->discussion.'&amp;parent='.$post->parent.'">'.get_string('parent', 'forum').'</a>';
2e2e71a8 3034 }
ce45515e 3035
add3201e 3036 if ($reply) {
3037 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.
3038 get_string('reply', 'forum').'</a>';
501cdbd8 3039 }
3040
add3201e 3041 $output .= '<div class="commands">';
3042 $output .= implode(' | ', $commands);
3043 $output .= '</div>';
3044
0a4ac01b 3045// Context link to post if required
501cdbd8 3046 if ($link) {
add3201e 3047 $output .= '<div class="link">';
0be4d8bf 3048 $output .= '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#p'.$post->id.'">'.
2b63df96 3049 get_string('postincontext', 'forum').'</a>';
add3201e 3050 $output .= '</div>';
501cdbd8 3051 }
add3201e 3052
501cdbd8 3053 if ($footer) {
add3201e 3054 $output .= '<div class="footer">'.$footer.'</div>';
501cdbd8 3055 }
add3201e 3056 $output .= '</td></tr></table>'."\n\n";
3057
501cdbd8 3058 return $output;
3059}
3060
0a4ac01b 3061/**
21976af1 3062 * Print a forum post
65bcf17b 3063 *
df1ba0f4 3064 * @global object
3065 * @global object
3066 * @uses FORUM_MODE_THREADED
3067 * @uses PORTFOLIO_FORMAT_PLAINHTML
3068 * @uses PORTFOLIO_FORMAT_FILE
3069 * @uses PORTFOLIO_FORMAT_RICHHTML
3070 * @uses PORTFOLIO_ADD_TEXT_LINK
3071 * @uses CONTEXT_MODULE
21976af1 3072 * @param object $post The post to print.
df1ba0f4 3073 * @param object $discussion
3074 * @param object $forum
3075 * @param object $cm
3076 * @param object $course
21976af1 3077 * @param boolean $ownpost Whether this post belongs to the current user.
65bcf17b 3078 * @param boolean $reply Whether to print a 'reply' link at the bottom of the message.
21976af1 3079 * @param boolean $link Just print a shortened version of the post as a link to the full post.
21976af1 3080 * @param string $footer Extra stuff to print after the message.
3081 * @param string $highlight Space-separated list of terms to highlight.
3082 * @param int $post_read true, false or -99. If we already know whether this user
3083 * has read this post, pass that in, otherwise, pass in -99, and this
3084 * function will work it out.
3085 * @param boolean $dummyifcantsee When forum_user_can_see_post says that
65bcf17b 3086 * the current user can't see this post, if this argument is true
21976af1 3087 * (the default) then print a dummy 'you can't see this post' post.
3088 * If false, don't output anything at all.
df1ba0f4 3089 * @param bool|null $istracked
63e87951 3090 * @return void
0a4ac01b 3091 */
65bcf17b 3092function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=false, $reply=false, $link=false,
63e87951 3093 $footer="", $highlight="", $post_read=null, $dummyifcantsee=true, $istracked=null) {
74f5d1e3 3094
5d9827e4 3095 global $USER, $CFG, $OUTPUT;
501cdbd8 3096
951e1073 3097 static $stredit, $strdelete, $strreply, $strparent, $strprune;
5d82704e 3098 static $strpruneheading, $displaymode;
90f4745c 3099 static $strmarkread, $strmarkunread;
f37da850 3100
8d96a7b4 3101 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
3102
65bcf17b 3103 $post->course = $course->id;
3104 $post->forum = $forum->id;
64f93798 3105 $post->message = file_rewrite_pluginfile_urls($post->message, 'pluginfile.php', $modcontext->id, 'mod_forum', 'post', $post->id);
951e1073 3106
65bcf17b 3107 // caching
3108 if (!isset($cm->cache)) {
3109 $cm->cache = new object();
3110 }
13bbe067 3111
65bcf17b 3112 if (!isset($cm->cache->caps)) {
3113 $cm->cache->caps = array();
65bcf17b 3114 $cm->cache->caps['mod/forum:viewdiscussion'] = has_capability('mod/forum:viewdiscussion', $modcontext);
3115 $cm->cache->caps['moodle/site:viewfullnames'] = has_capability('moodle/site:viewfullnames', $modcontext);
3116 $cm->cache->caps['mod/forum:editanypost'] = has_capability('mod/forum:editanypost', $modcontext);
3117 $cm->cache->caps['mod/forum:splitdiscussions'] = has_capability('mod/forum:splitdiscussions', $modcontext);
3118 $cm->cache->caps['mod/forum:deleteownpost'] = has_capability('mod/forum:deleteownpost', $modcontext);
3119 $cm->cache->caps['mod/forum:deleteanypost'] = has_capability('mod/forum:deleteanypost', $modcontext);
3120 $cm->cache->caps['mod/forum:viewanyrating'] = has_capability('mod/forum:viewanyrating', $modcontext);
f98b13a6 3121 $cm->cache->caps['mod/forum:exportpost'] = has_capability('mod/forum:exportpost', $modcontext);
3122 $cm->cache->caps['mod/forum:exportownpost'] = has_capability('mod/forum:exportownpost', $modcontext);
951e1073 3123 }
951e1073 3124
65bcf17b 3125 if (!isset($cm->uservisible)) {
3126 $cm->uservisible = coursemodule_visible_for_user($cm);
3127 }
3128
3129 if (!forum_user_can_see_post($forum, $discussion, $post, NULL, $cm)) {
21976af1 3130 if (!$dummyifcantsee) {
098d27d4 3131 return;
2b63df96 3132 }
0be4d8bf 3133 echo '<a id="p'.$post->id.'"></a>';
098d27d4 3134 echo '<table cellspacing="0" class="forumpost">';
3135 echo '<tr class="header"><td class="picture left">';
3136 // print_user_picture($post->userid, $courseid, $post->picture);