Added the search_generate_text_SQL() function that generates
[moodle.git] / mod / forum / lib.php
CommitLineData
41905731 1<?php // $Id$
f93f848a 2
f1e0649c 3require_once($CFG->libdir.'/filelib.php');
7f6689e4 4
501cdbd8 5/// CONSTANTS ///////////////////////////////////////////////////////////
f93f848a 6
d3583b41 7define('FORUM_MODE_FLATOLDEST', 1);
8define('FORUM_MODE_FLATNEWEST', -1);
9define('FORUM_MODE_THREADED', 2);
10define('FORUM_MODE_NESTED', 3);
2e2e71a8 11
d3583b41 12define('FORUM_FORCESUBSCRIBE', 1);
13define('FORUM_INITIALSUBSCRIBE', 2);
098d27d4 14define('FORUM_DISALLOWSUBSCRIBE',3);
709f0ec8 15
eaf50aef 16define('FORUM_TRACKING_OFF', 0);
17define('FORUM_TRACKING_OPTIONAL', 1);
18define('FORUM_TRACKING_ON', 2);
19
1a7cdb11 20define('FORUM_UNSET_POST_RATING', -999);
21
d3583b41 22$FORUM_LAYOUT_MODES = array ( FORUM_MODE_FLATOLDEST => get_string('modeflatoldestfirst', 'forum'),
23 FORUM_MODE_FLATNEWEST => get_string('modeflatnewestfirst', 'forum'),
24 FORUM_MODE_THREADED => get_string('modethreaded', 'forum'),
25 FORUM_MODE_NESTED => get_string('modenested', 'forum') );
f93f848a 26
11b0c469 27// These are course content forums that can be added to the course manually
d3583b41 28$FORUM_TYPES = array ('general' => get_string('generalforum', 'forum'),
29 'eachuser' => get_string('eachuserforum', 'forum'),
098d27d4 30 'single' => get_string('singleforum', 'forum'),
31 'qanda' => get_string('qandaforum', 'forum')
32 );
f93f848a 33
d3583b41 34$FORUM_OPEN_MODES = array ('2' => get_string('openmode2', 'forum'),
35 '1' => get_string('openmode1', 'forum'),
36 '0' => get_string('openmode0', 'forum') );
70c476a7 37
5be7800c 38if (!isset($CFG->forum_displaymode)) {
d3583b41 39 set_config('forum_displaymode', FORUM_MODE_NESTED);
65b0e537 40}
73bb0835 41
5be7800c 42if (!isset($CFG->forum_shortpost)) {
d3583b41 43 set_config('forum_shortpost', 300); // Less non-HTML characters than this is short
65b0e537 44}
4d871a72 45
5be7800c 46if (!isset($CFG->forum_longpost)) {
d3583b41 47 set_config('forum_longpost', 600); // More non-HTML characters than this is long
65b0e537 48}
4d871a72 49
5be7800c 50if (!isset($CFG->forum_manydiscussions)) {
d3583b41 51 set_config('forum_manydiscussions', 100); // Number of discussions on a page
65b0e537 52}
e07635f4 53
4909e176 54if (!isset($CFG->forum_maxbytes)) {
d3583b41 55 set_config('forum_maxbytes', 512000); // Default maximum size for all forums
65b0e537 56}
4909e176 57
f37da850 58if (!isset($CFG->forum_trackreadposts)) {
d3583b41 59 set_config('forum_trackreadposts', true); // Default whether user needs to mark a post as read
f37da850 60}
61
62if (!isset($CFG->forum_oldpostdays)) {
81c679ce 63 set_config('forum_oldpostdays', 14); // Default number of days that a post is considered old
f37da850 64}
65
66if (!isset($CFG->forum_usermarksread)) {
d3583b41 67 set_config('forum_usermarksread', false); // Default whether user needs to mark a post as read
f37da850 68}
69
70if (!isset($CFG->forum_cleanreadtime)) {
d3583b41 71 set_config('forum_cleanreadtime', 2); // Default time (hour) to execute 'clean_read_records' cron
f37da850 72}
73
1246ea56 74if (!isset($CFG->forum_replytouser)) {
d3583b41 75 set_config('forum_replytouser', true); // Default maximum size for all forums
1246ea56 76}
77
27888a20 78if (empty($USER->id) or isguest()) {
79 $CFG->forum_trackreadposts = false; // This feature never works when a user isn't logged in
80}
4909e176 81
3d284127 82if (!isset($CFG->forum_enabletimedposts)) { // Newish feature that is not quite ready for production in 1.6
83 $CFG->forum_enabletimedposts = false;
84}
85
e07635f4 86
caadf009 87/// STANDARD FUNCTIONS ///////////////////////////////////////////////////////////
88
89function forum_add_instance($forum) {
65b0e537 90// Given an object containing all the necessary data,
91// (defined by the form in mod.html) this function
92// will create a new instance and return the id number
caadf009 93// of the new instance.
94
95 global $CFG;
96
97 $forum->timemodified = time();
98
4f93f5ba 99 if (!isset($forum->assessed)) {
f2f56406 100 $forum->assessed = 0;
101 }
2b63df96 102
535e0ab6 103 if (empty($forum->ratingtime)) {
98914efd 104 $forum->assesstimestart = 0;
105 $forum->assesstimefinish = 0;
106 }
caadf009 107
0fa18d5a 108 if (!$forum->id = insert_record('forum', $forum)) {
cb9a975f 109 return false;
110 }
111
d3583b41 112 if ($forum->type == 'single') { // Create related discussion.
caadf009 113 $discussion->course = $forum->course;
114 $discussion->forum = $forum->id;
115 $discussion->name = $forum->name;
116 $discussion->intro = $forum->intro;
117 $discussion->assessed = $forum->assessed;
93c86520 118 $discussion->format = $forum->format;
41547057 119 $discussion->mailnow = false;
caadf009 120
93c86520 121 if (! forum_add_discussion($discussion, $discussion->intro)) {
d3583b41 122 error('Could not add the discussion for this forum');
caadf009 123 }
124 }
8f0cd6ef 125
709f0ec8 126 if ($forum->forcesubscribe == FORUM_INITIALSUBSCRIBE) { // all users should be subscribed initially
127 $users = get_course_users($forum->course);
128 foreach ($users as $user) {
129 forum_subscribe($user->id, $forum->id);
130 }
131 }
caadf009 132
133 return $forum->id;
134}
135
136
137function forum_update_instance($forum) {
65b0e537 138// Given an object containing all the necessary data,
139// (defined by the form in mod.html) this function
caadf009 140// will update an existing instance with new data.
141
142 $forum->timemodified = time();
143 $forum->id = $forum->instance;
144
f0da6b85 145 if (empty($forum->assessed)) {
f2f56406 146 $forum->assessed = 0;
147 }
2b63df96 148
6e372b25 149 if (empty($forum->ratingtime)) {
98914efd 150 $forum->assesstimestart = 0;
151 $forum->assesstimefinish = 0;
152 }
153
d3583b41 154 if ($forum->type == 'single') { // Update related discussion and post.
155 if (! $discussion = get_record('forum_discussions', 'forum', $forum->id)) {
156 if ($discussions = get_records('forum_discussions', 'forum', $forum->id, 'timemodified ASC')) {
157 notify('Warning! There is more than one discussion in this forum - using the most recent');
caadf009 158 $discussion = array_pop($discussions);
159 } else {
d3583b41 160 error('Could not find the discussion in this forum');
caadf009 161 }
162 }
d3583b41 163 if (! $post = get_record('forum_posts', 'id', $discussion->firstpost)) {
164 error('Could not find the first post in this forum discussion');
caadf009 165 }
166
167 $post->subject = $forum->name;
168 $post->message = $forum->intro;
169 $post->modified = $forum->timemodified;
170
d3583b41 171 if (! update_record('forum_posts', $post)) {
172 error('Could not update the first post');
caadf009 173 }
174
175 $discussion->name = $forum->name;
176
d3583b41 177 if (! update_record('forum_discussions', $discussion)) {
178 error('Could not update the discussion');
caadf009 179 }
180 }
181
d3583b41 182 return update_record('forum', $forum);
caadf009 183}
184
185
186function forum_delete_instance($id) {
65b0e537 187// Given an ID of an instance of this module,
188// this function will permanently delete the instance
189// and any data that depends on it.
caadf009 190
0fa18d5a 191 if (!$forum = get_record('forum', 'id', $id)) {
caadf009 192 return false;
193 }
194
195 $result = true;
196
d3583b41 197 if ($discussions = get_records('forum_discussions', 'forum', $forum->id)) {
caadf009 198 foreach ($discussions as $discussion) {
0fa18d5a 199 if (!forum_delete_discussion($discussion, true)) {
caadf009 200 $result = false;
201 }
202 }
203 }
204
0fa18d5a 205 if (!delete_records('forum_subscriptions', 'forum', $forum->id)) {
caadf009 206 $result = false;
207 }
208
f37da850 209 forum_tp_delete_read_records(-1, -1, -1, $forum->id);
210
0fa18d5a 211 if (!delete_records('forum', 'id', $forum->id)) {
caadf009 212 $result = false;
213 }
214
215 return $result;
216}
217
218
0fa18d5a 219function forum_cron() {
5fac3a5e 220
edffca15 221/// Function to be run periodically according to the moodle cron
222/// Finds all posts that have yet to be mailed out, and mails them
223/// out to all subscribers
caadf009 224
d30867b0 225 global $CFG, $USER;
aaf7a9dc 226 static $strforums = NULL;
857b798b 227
669f2499 228 static $cachecm = array();
229
857b798b 230 if ($strforums === NULL) {
aaf7a9dc 231 $strforums = get_string('forums', 'forum');
232 }
233
9152fc99 234 $realuser = clone($USER);
ec2137ba 235
3ecca1ee 236 /// Posts older than 2 days will not be mailed. This is to avoid the problem where
237 /// cron has not been running for a long time, and then suddenly people are flooded
238 /// with mail from the past few weeks or months
caadf009 239
3ecca1ee 240 $timenow = time();
241 $endtime = $timenow - $CFG->maxeditingtime;
38ad519c 242 $starttime = $endtime - 48 * 3600; /// Two days earlier
3ecca1ee 243
669f2499 244 $CFG->enablerecordcache = true; // We want all the caching we can get
5fac3a5e 245
246 // all users that are subscribed to any post that needs sending
247 $users = array();
248
249 $mailcount=array();
250 $errorcount=array();
251
252 $postsinfo = array();
253 $subscribedusers = array();
254
255 if ($posts = forum_get_unmailed_posts($starttime, $endtime)) {
16b4e5b6 256 /// Mark them all now as being mailed. It's unlikely but possible there
257 /// might be an error later so that a post is NOT actually mailed out,
258 /// but since mail isn't crucial, we can accept this risk. Doing it now
259 /// prevents the risk of duplicated mails, which is a worse problem.
260
5fac3a5e 261 if (!forum_mark_old_posts_as_mailed($endtime)) {
262 mtrace('Errors occurred while trying to mark some posts as being mailed.');
263 return false; // Don't continue trying to mail them, in case we are in a cron loop
264 }
265
266 // checking post validity, and adding users to loop through later
267 foreach ($posts as $pid => $post) {
268
269 if (! $discussion = get_record('forum_discussions', 'id', $post->discussion)) {
270 mtrace('Could not find discussion '.$post->discussion);
271 unset($posts[$pid]);
272 continue;
273 }
274
275 if (! $forum = get_record('forum', 'id', $discussion->forum)) {
276 mtrace('Could not find forum '.$discussion->forum);
277 unset($posts[$pid]);
278 continue;
279 }
669f2499 280
5fac3a5e 281 if (! $course = get_record('course', 'id', $forum->course)) {
282 mtrace('Could not find course '.$forum->course);
283 unset($posts[$pid]);
284 continue;
285 }
286
4dad2828 287 // Caching this environment info so we don't need to look them up later
288 // There is still a LOT of duplication here we could cut down on. XXX TODO
289
5fac3a5e 290 unset($pinfo);
4dad2828 291 $pinfo->discussion = $discussion;
292 $pinfo->forum = $forum;
293 $pinfo->course = $course;
5fac3a5e 294
295 $postinfo[$pid] = $pinfo;
296
297 // caching subscribed users of each forum
298 if (!isset($subscribedusers[$forum->id])) {
704ca25c 299 if ($subusers = forum_subscribed_users($course, $forum, 0, true)) {
300 foreach ($subusers as $postuser) {
301 // this user is subscribed to this forum
302 $subscribedusers[$forum->id][] = $postuser->id;
303 // this user is a user we have to process later
304 $users[$postuser->id] = $postuser;
305 }
5fac3a5e 306 }
307 }
308
309 $mailcount[$pid] = 0;
310 $errorcount[$pid] = 0;
311 }
312 }
caadf009 313
4dad2828 314 if ($users && $posts) {
edffca15 315
ca8e8a10 316 @set_time_limit(0); /// so that script does not get timed out when posting to many users
aaf7a9dc 317
857b798b 318 $urlinfo = parse_url($CFG->wwwroot);
319 $hostname = $urlinfo['host'];
320
4dad2828 321 ksort($users);
322
5fac3a5e 323 foreach ($users as $userto) {
324
4dad2828 325 // set this so that the capabilities are cached, and environment matches receiving user
5fac3a5e 326 $USER = $userto;
327
16b4e5b6 328 mtrace('Processing user '.$userto->id);
caadf009 329
4dad2828 330 /// we might want to add another layer - forums here (by checking array_keys($subscribedusers))
331 /// so that we can skip many posts
669f2499 332
4dad2828 333 foreach ($posts as $pid => $post) {
caadf009 334
4dad2828 335 // Get info about the sending user XXX TODO cache these and get needed fields only
caadf009 336
4dad2828 337 if (! $userfrom = get_record('user', 'id', $post->userid)) {
338 mtrace('Could not find user '.$post->userid);
339 continue;
340 }
918e9805 341
4dad2828 342 // Set up the environment for the post, discussion, forum, course
343
344 $discussion = $postinfo[$pid]->discussion;
345 $forum = $postinfo[$pid]->forum;
346 $course = $postinfo[$pid]->course;
347
348 course_setup($course); // More environment
349
350
351 // Do some checks to see if we can bail out now
352
353 if (empty($subscribedusers[$forum->id]) || !in_array($userto->id, $subscribedusers[$forum->id])) {
354 continue; // user does not subscribe to this forum
355 }
356
357
358 // Get the coursemodule and context (cached)
359
360 if (!empty($cachecm[$forum->id])) {
361 $cm = $cachecm[$forum->id];
362
363 } else if ($cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
364 $cachecm[$forum->id] = $cm;
365
366 } else {
367 $cm = new object;
368 $cm->id = 0;
369 $cachecm[$forum->id] = $cm;
370 }
371
372 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id); // Cached already
373
374
375 // Make sure groups allow this user to see this email
376
377 $groupmode = false;
378 if (!empty($cm->id)) {
379 if ($groupmode = groupmode($course, $cm) and $discussion->groupid > 0) { // Groups are being used
380 if (! groups_group_exists($discussion->groupid)) { // Can't find group //TODO:
381 continue; // Be safe and don't send it to anyone
5fac3a5e 382 }
383 }
4dad2828 384 }
918e9805 385
4dad2828 386 if ($groupmode) { // Look for a reason not to send this email
387 if (!empty($group->id)) {
388 if (!ismember($group->id, $userto->id)) {
389 if (!has_capability('moodle/site:accessallgroups', $modcontext)) {
390 continue;
9197e147 391 }
392 }
393 }
4dad2828 394 }
2b63df96 395
65b0e537 396
4dad2828 397 // Make sure we're allowed to see it...
398 if (!forum_user_can_see_post($forum, $discussion, $post)) {
399 mtrace('user '.$userto->id. ' can not see '.$post->id);
400 continue;
401 }
402
403 // OK so we need to send the email.
404
405 // Does the user want this post in a digest? If so postpone it for now.
406 if ($userto->maildigest > 0) {
407 // This user wants the mails to be in digest form
408 $queue = New stdClass;
409 $queue->userid = $userto->id;
410 $queue->discussionid = $discussion->id;
411 $queue->postid = $post->id;
412 if (!insert_record('forum_queue', $queue)) {
413 mtrace("Error: mod/forum/cron.php: Could not queue for digest mail for id $post->id to user $userto->id ($userto->email) .. not trying again.");
aaf7a9dc 414 }
4dad2828 415 continue;
416 }
65b0e537 417
4dad2828 418
419 // Prepare to actually send the post now, and build up the content
420
421 $cleanforumname = str_replace('"', "'", strip_tags($forum->name));
422
423 $userfrom->customheaders = array ( // Headers to make emails easier to track
424 'Precedence: Bulk',
425 'List-Id: "'.$cleanforumname.'" <moodleforum'.$forum->id.'@'.$hostname.'>',
426 'List-Help: '.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id,
427 'Message-ID: <moodlepost'.$post->id.'@'.$hostname.'>',
428 'In-Reply-To: <moodlepost'.$post->parent.'@'.$hostname.'>',
429 'References: <moodlepost'.$post->parent.'@'.$hostname.'>',
430 'X-Course-Id: '.$course->id,
431 'X-Course-Name: '.strip_tags($course->fullname)
432 );
433
434
435 $postsubject = "$course->shortname: ".format_string($post->subject,true);
436 $posttext = forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto);
437 $posthtml = forum_make_mail_html($course, $forum, $discussion, $post, $userfrom, $userto);
438
439 // Send the post now!
440
441 mtrace('Sending ', '');
442
443 if (!$mailresult = email_to_user($userto, $userfrom, $postsubject, $posttext,
444 $posthtml, '', '', $CFG->forum_replytouser)) {
445 mtrace("Error: mod/forum/cron.php: Could not send out mail for id $post->id to user $userto->id".
446 " ($userto->email) .. not trying again.");
447 add_to_log($course->id, 'forum', 'mail error', "discuss.php?d=$discussion->id#p$post->id",
448 substr(format_string($post->subject,true),0,30), $cm->id, $userto->id);
449 $errorcount[$post->id]++;
450 } else if ($mailresult === 'emailstop') {
451 add_to_log($course->id, 'forum', 'mail blocked', "discuss.php?d=$discussion->id#p$post->id",
452 substr(format_string($post->subject,true),0,30), $cm->id, $userto->id);
453 } else {
454 $mailcount[$post->id]++;
455
456 /// Mark post as read if forum_usermarksread is set off
457 if (!$CFG->forum_usermarksread && forum_tp_can_track_forums($forum, $userto) &&
458 forum_tp_is_tracked($forum, $userto->id)) {
459 if (!forum_tp_mark_post_read($userto->id, $post, $forum->id)) {
460 mtrace("Error: mod/forum/cron.php: Could not mark post $post->id read for user $userto->id".
461 " while sending email.");
f37da850 462 }
caadf009 463 }
aaf7a9dc 464 }
4dad2828 465
466 mtrace('post '.$post->id. ': '.$post->subject);
aaf7a9dc 467 }
5fac3a5e 468 }
469 }
470
471 if ($posts) {
472 foreach ($posts as $post) {
16b4e5b6 473 mtrace($mailcount[$post->id]." users were sent post $post->id, '$post->subject'");
5fac3a5e 474 if ($errorcount[$post->id]) {
475 set_field("forum_posts", "mailed", "2", "id", "$post->id");
476 }
aaf7a9dc 477 }
478 }
479
9152fc99 480 $sitetimezone = $CFG->timezone;
944a2b28 481
aaf7a9dc 482 /// Now see if there are any digest mails waiting to be sent, and if we should send them
aaf7a9dc 483
8f0cd6ef 484 if (!isset($CFG->digestmailtimelast)) { // To catch the first time
ca8e8a10 485 set_config('digestmailtimelast', 0);
486 }
487
488 $timenow = time();
944a2b28 489 $digesttime = usergetmidnight($timenow, $sitetimezone) + ($CFG->digestmailtime * 3600);
ca8e8a10 490
491 if ($CFG->digestmailtimelast < $digesttime and $timenow > $digesttime) {
b140ae85 492
ca8e8a10 493 set_config('digestmailtimelast', $timenow);
aaf7a9dc 494
b140ae85 495 mtrace('Sending forum digests: '.userdate($timenow, '', $sitetimezone));
496
aaf7a9dc 497 $digestposts = get_records('forum_queue');
498 if(!empty($digestposts)) {
499
8ad64455 500 @set_time_limit(0); /// so that script does not get timed out when posting to many users
501
aaf7a9dc 502 // We have work to do
503 $usermailcount = 0;
504 $site = get_site();
505
506 $users = array();
507 $posts = array();
508 $discussions = array();
509 $discussionposts = array();
510 $userdiscussions = array();
511 foreach($digestposts as $digestpost) {
512 if(!isset($users[$digestpost->userid])) {
513 $users[$digestpost->userid] = get_record('user', 'id', $digestpost->userid);
514 }
515 if(!isset($discussions[$digestpost->discussionid])) {
516 $discussions[$digestpost->discussionid] = get_record('forum_discussions', 'id', $digestpost->discussionid);
517 }
518 if(!isset($posts[$digestpost->postid])) {
519 $posts[$digestpost->postid] = get_record('forum_posts', 'id', $digestpost->postid);
520 }
521 $userdiscussions[$digestpost->userid][$digestpost->discussionid] = $digestpost->discussionid;
522 $discussionposts[$digestpost->discussionid][$digestpost->postid] = $digestpost->postid;
523 }
524
525 // Data collected, start sending out emails to each user
526
527 foreach($userdiscussions as $userid => $thesediscussions) {
528
b140ae85 529 mtrace(get_string('processingdigest', 'forum', $userid),'... ');
aaf7a9dc 530
531 // First of all delete all the queue entries for this user
532 delete_records('forum_queue', 'userid', $userid);
533 $userto = $users[$userid];
534
535 /// Override the language and timezone of the "current" user, so that
536 /// mail is customised for the receiver.
9152fc99 537 $USER = $userto;
538 course_setup(SITEID);
aaf7a9dc 539
540
541 $postsubject = get_string('digestmailsubject', 'forum', $site->shortname);
542 $headerdata = New stdClass;
543 $headerdata->sitename = $site->fullname;
839f2456 544 $headerdata->userprefs = $CFG->wwwroot.'/user/edit.php?id='.$userid.'&amp;course='.$site->id;
aaf7a9dc 545
546 $posttext = get_string('digestmailheader', 'forum', $headerdata)."\n\n";
547 $headerdata->userprefs = '<a target="_blank" href="'.$headerdata->userprefs.'">'.get_string('digestmailprefs', 'forum').'</a>';
9c674431 548
78c0d909 549 $posthtml = "<head>";
550 foreach ($CFG->stylesheets as $stylesheet) {
551 $posthtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
552 }
553 $posthtml .= "</head>\n<body>\n";
a0330747 554 $posthtml .= '<p>'.get_string('digestmailheader', 'forum', $headerdata).'</p><br /><hr size="1" noshade="noshade" />';
aaf7a9dc 555
556 foreach($thesediscussions as $discussionid) {
557 $discussion = $discussions[$discussionid];
558 if(empty($discussion)) {
b140ae85 559 mtrace("Error: Could not find discussion $discussionid");
aaf7a9dc 560 continue;
caadf009 561 }
aaf7a9dc 562
563 if (! $forum = get_record("forum", "id", "$discussion->forum")) {
b140ae85 564 mtrace("Could not find forum $discussion->forum");
aaf7a9dc 565 continue;
f690562f 566 }
aaf7a9dc 567 if (! $course = get_record("course", "id", "$forum->course")) {
b140ae85 568 mtrace("Could not find course $forum->course");
aaf7a9dc 569 continue;
caadf009 570 }
65b0e537 571
9152fc99 572 //override language
573 course_setup($course);
574
aaf7a9dc 575 $canunsubscribe = ! forum_is_forcesubscribed($forum->id);
576 $canreply = forum_user_can_post($forum, $userto);
caadf009 577
caadf009 578
aaf7a9dc 579 $posttext .= "\n \n";
580 $posttext .= '=====================================================================';
581 $posttext .= "\n \n";
3849dae8 582 $posttext .= "$course->shortname -> $strforums -> ".format_string($forum->name,true);
aaf7a9dc 583 if ($discussion->name != $forum->name) {
c78ac798 584 $posttext .= " -> ".format_string($discussion->name,true);
caadf009 585 }
aaf7a9dc 586 $posttext .= "\n";
65b0e537 587
aaf7a9dc 588 $posthtml .= "<p><font face=\"sans-serif\">".
589 "<a target=\"_blank\" href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> -> ".
590 "<a target=\"_blank\" href=\"$CFG->wwwroot/mod/forum/index.php?id=$course->id\">$strforums</a> -> ".
3849dae8 591 "<a target=\"_blank\" href=\"$CFG->wwwroot/mod/forum/view.php?f=$forum->id\">".format_string($forum->name,true)."</a>";
aaf7a9dc 592 if ($discussion->name == $forum->name) {
593 $posthtml .= "</font></p>";
caadf009 594 } else {
c78ac798 595 $posthtml .= " -> <a target=\"_blank\" href=\"$CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id\">".format_string($discussion->name,true)."</a></font></p>";
caadf009 596 }
aaf7a9dc 597 $posthtml .= '<p>';
598
e1c6dde1 599 $postsarray = $discussionposts[$discussionid];
600 sort($postsarray);
601
f37da850 602 /// Create an empty array to use for marking read posts.
603 /// (I'm sure there's already a structure I can use here, but I can't be sure.)
604 $markread = array();
605
857b798b 606 foreach ($postsarray as $postid) {
aaf7a9dc 607 if (! $post = get_record("forum_posts", "id", "$postid")) {
b140ae85 608 mtrace("Error: Could not find post $postid");
aaf7a9dc 609 continue;
610 }
611 if (! $userfrom = get_record("user", "id", "$post->userid")) {
b140ae85 612 mtrace("Error: Could not find user $post->userid");
aaf7a9dc 613 continue;
614 }
615
857b798b 616 $userfrom->customheaders = array ("Precedence: Bulk");
617
618 if ($userto->maildigest == 2) {
aaf7a9dc 619 // Subjects only
620 $by = New stdClass;
621 $by->name = fullname($userfrom);
622 $by->date = userdate($post->modified);
17dc3f3c 623 $posttext .= "\n".format_string($post->subject,true).' '.get_string("bynameondate", "forum", $by);
aaf7a9dc 624 $posttext .= "\n---------------------------------------------------------------------";
625
839f2456 626 $by->name = "<a target=\"_blank\" href=\"$CFG->wwwroot/user/view.php?id=$userfrom->id&amp;course=$course->id\">$by->name</a>";
0be4d8bf 627 $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 628
629 } else {
aaf7a9dc 630 // The full treatment
631 $posttext .= forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto, true);
add3201e 632 $posthtml .= forum_make_mail_post($post, $userfrom, $userto, $course, false, $canreply, true, false);
f37da850 633
634 /// Create an array of postid's for this user to mark as read.
2b63df96 635 if (!$CFG->forum_usermarksread &&
636 forum_tp_can_track_forums($forum, $userto) &&
eaf50aef 637 forum_tp_is_tracked($forum, $userto->id)) {
f37da850 638 $markread[$post->id]->post = $post;
639 $markread[$post->id]->forumid = $forum->id;
640 }
aaf7a9dc 641 }
642 }
643 if ($canunsubscribe) {
644 $posthtml .= "\n<div align=\"right\"><font size=\"1\"><a href=\"$CFG->wwwroot/mod/forum/subscribe.php?id=$forum->id\">".get_string("unsubscribe", "forum")."</a></font></div>";
857b798b 645 } else {
aaf7a9dc 646 $posthtml .= "\n<div align=\"right\"><font size=\"1\">".get_string("everyoneissubscribed", "forum")."</font></div>";
647 }
648 $posthtml .= '<hr size="1" noshade="noshade" /></p>';
caadf009 649 }
a0330747 650 $posthtml .= '</body>';
caadf009 651
379a42cb 652 if($userto->mailformat != 1) {
653 // This user DOESN'T want to receive HTML
654 $posthtml = '';
655 }
656
8f0cd6ef 657 if (!$mailresult = email_to_user($userto, $site->shortname, $postsubject, $posttext, $posthtml,
50a26903 658 '', '', $CFG->forum_replytouser)) {
b140ae85 659 mtrace("ERROR!");
aaf7a9dc 660 echo "Error: mod/forum/cron.php: Could not send out digest mail to user $userto->id ($userto->email)... not trying again.\n";
661 add_to_log($course->id, 'forum', 'mail digest error', '', '', $cm->id, $userto->id);
b6268a0e 662 } else if ($mailresult === 'emailstop') {
50a26903 663 add_to_log($course->id, 'forum', 'mail digest blocked', '', '', $cm->id, $userto->id);
aaf7a9dc 664 } else {
b140ae85 665 mtrace("success.");
aaf7a9dc 666 $usermailcount++;
e3ff14ca 667
6ea5ebd4 668 /// Mark post as read if forum_usermarksread is set off
2b63df96 669 if (!$CFG->forum_usermarksread &&
670 forum_tp_can_track_forums($forum->id, $userto) &&
6ea5ebd4 671 forum_tp_is_tracked($forum->id, $userto->id)) {
672 foreach ($markread as $postinfo) {
673 if (!forum_tp_mark_post_read($userto->id, $postinfo->post, $postinfo->forumid)) {
674 mtrace("Error: mod/forum/cron.php: Could not mark post $postid read for user $userto->id".
675 " while sending digest email.");
f37da850 676 }
677 }
6ea5ebd4 678 }
3d94772d 679 }
caadf009 680 }
caadf009 681 }
682 }
683
d658167f 684 if(!empty($usermailcount)) {
b140ae85 685 mtrace(get_string('digestsentusers', 'forum', $usermailcount));
aaf7a9dc 686 }
687
9152fc99 688 $USER = $realuser;
689 course_setup(SITEID); // reset cron user language, theme and timezone settings
ec2137ba 690
8ad64455 691 if (!empty($CFG->forum_lastreadclean)) {
f37da850 692 $timenow = time();
8ad64455 693 if ($CFG->forum_lastreadclean + (24*3600) < $timenow) {
694 set_config('forum_lastreadclean', $timenow);
f37da850 695 forum_tp_clean_read_records();
696 }
697 } else {
8ad64455 698 set_config('forum_lastreadclean', time());
f37da850 699 }
700
701
caadf009 702 return true;
703}
704
16b4e5b6 705
aaf7a9dc 706function forum_make_mail_text($course, $forum, $discussion, $post, $userfrom, $userto, $bare = false) {
15f81ee3 707 global $CFG, $USER;
2b63df96 708
0fa18d5a 709 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id)) {
710 error('Course Module ID was incorrect');
711 }
712 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
33e21153 713 $viewfullnames = has_capability('moodle/site:viewfullnames', $modcontext);
2b63df96 714
aaf7a9dc 715 $by = New stdClass;
0fa18d5a 716 $by->name = fullname($userfrom, $viewfullnames);
aaf7a9dc 717 $by->date = userdate($post->modified, "", $userto->timezone);
718
719 $strbynameondate = get_string('bynameondate', 'forum', $by);
720
64762ddc 721 $strforums = get_string('forums', 'forum');
722
aaf7a9dc 723 $canunsubscribe = ! forum_is_forcesubscribed($forum->id);
724 $canreply = forum_user_can_post($forum, $userto);
725
726 $posttext = '';
727
0fa18d5a 728 if (!$bare) {
3849dae8 729 $posttext = "$course->shortname -> $strforums -> ".format_string($forum->name,true);
aaf7a9dc 730
731 if ($discussion->name != $forum->name) {
c78ac798 732 $posttext .= " -> ".format_string($discussion->name,true);
aaf7a9dc 733 }
734 }
735
736 $posttext .= "\n---------------------------------------------------------------------\n";
17dc3f3c 737 $posttext .= format_string($post->subject,true);
0fa18d5a 738 if ($bare) {
0be4d8bf 739 $posttext .= " ($CFG->wwwroot/mod/forum/discuss.php?d=$discussion->id#p$post->id)";
aaf7a9dc 740 }
741 $posttext .= "\n".$strbynameondate."\n";
742 $posttext .= "---------------------------------------------------------------------\n";
f2b5d7e3 743 $posttext .= format_text_email(trusttext_strip($post->message), $post->format);
aaf7a9dc 744 $posttext .= "\n\n";
745 if ($post->attachment) {
746 $post->course = $course->id;
747 $post->forum = $forum->id;
748 $posttext .= forum_print_attachments($post, "text");
749 }
750 if (!$bare && $canreply) {
751 $posttext .= "---------------------------------------------------------------------\n";
752 $posttext .= get_string("postmailinfo", "forum", $course->shortname)."\n";
753 $posttext .= "$CFG->wwwroot/mod/forum/post.php?reply=$post->id\n";
754 }
755 if (!$bare && $canunsubscribe) {
756 $posttext .= "\n---------------------------------------------------------------------\n";
757 $posttext .= get_string("unsubscribe", "forum");
758 $posttext .= ": $CFG->wwwroot/mod/forum/subscribe.php?id=$forum->id\n";
759 }
760
761 return $posttext;
762}
763
764function forum_make_mail_html($course, $forum, $discussion, $post, $userfrom, $userto) {
765 global $CFG;
766
a0288610 767 if ($userto->mailformat != 1) { // Needs to be HTML
768 return '';
769 }
aaf7a9dc 770
a0288610 771 $strforums = get_string('forums', 'forum');
772 $canreply = forum_user_can_post($forum, $userto);
918e9805 773 $canunsubscribe = ! $forum->forcesubscribe;
aaf7a9dc 774
a0288610 775 $posthtml = '<head>';
776 foreach ($CFG->stylesheets as $stylesheet) {
777 $posthtml .= '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'" />'."\n";
778 }
779 $posthtml .= '</head>';
f2379d2d 780 $posthtml .= "\n<body id=\"email\">\n\n";
aaf7a9dc 781
f2379d2d 782 $posthtml .= '<div class="navbar">'.
a0288610 783 '<a target="_blank" href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">'.$course->shortname.'</a> &raquo; '.
784 '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/index.php?id='.$course->id.'">'.$strforums.'</a> &raquo; '.
785 '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'">'.format_string($forum->name,true).'</a>';
786 if ($discussion->name == $forum->name) {
787 $posthtml .= '</div>';
aaf7a9dc 788 } else {
a0288610 789 $posthtml .= ' &raquo; <a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion->id.'">'.
790 format_string($discussion->name,true).'</a></div>';
aaf7a9dc 791 }
a0288610 792 $posthtml .= forum_make_mail_post($post, $userfrom, $userto, $course, false, $canreply, true, false);
793
794 if ($canunsubscribe) {
795 $posthtml .= '<br /><div class="unsubscribelink"><a href="'.$CFG->wwwroot.'/mod/forum/subscribe.php?id='.$forum->id.'">'.
796 get_string('unsubscribe', 'forum').'</a></div>';
797 }
798
f2379d2d 799 $posthtml .= '</body>';
800
a0288610 801 return $posthtml;
aaf7a9dc 802}
803
caadf009 804function forum_user_outline($course, $user, $mod, $forum) {
805
1f48942e 806 if ($posts = forum_get_user_posts($forum->id, $user->id)) {
caadf009 807 $result->info = get_string("numposts", "forum", count($posts));
808
809 $lastpost = array_pop($posts);
810 $result->time = $lastpost->modified;
811 return $result;
812 }
813 return NULL;
814}
815
816
817function forum_user_complete($course, $user, $mod, $forum) {
818 global $CFG;
819
1f48942e 820 if ($posts = forum_get_user_posts($forum->id, $user->id)) {
caadf009 821 foreach ($posts as $post) {
e3ff14ca 822
f37da850 823 $post->forum = $forum->id;
497588fe 824 forum_print_post($post, $course->id, $ownpost=false, $reply=false, $link=false, $rate=false);
caadf009 825 }
826
827 } else {
41905731 828 echo "<p>".get_string("noposts", "forum")."</p>";
caadf009 829 }
caadf009 830}
831
185cfb09 832function forum_print_overview($courses,&$htmlarray) {
0d6b9d4f 833 global $USER, $CFG;
a8f4522d 834 $LIKE = sql_ilike();
9cba7a8c 835
185cfb09 836 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
837 return array();
838 }
f8716988 839
185cfb09 840 if (!$forums = get_all_instances_in_courses('forum',$courses)) {
f8716988 841 return;
842 }
185cfb09 843
5aa23eea 844
f8716988 845 // get all forum logs in ONE query (much better!)
185cfb09 846 $sql = "SELECT instance,cmid,l.course,COUNT(l.id) as count FROM {$CFG->prefix}log l "
847 ." JOIN {$CFG->prefix}course_modules cm ON cm.id = cmid "
848 ." WHERE (";
849 foreach ($courses as $course) {
850 $sql .= '(l.course = '.$course->id.' AND l.time > '.$course->lastaccess.') OR ';
851 }
852 $sql = substr($sql,0,-3); // take off the last OR
853
a8f4522d 854 $sql .= ") AND l.module = 'forum' AND action $LIKE 'add post%' "
185cfb09 855 ." AND userid != ".$USER->id." GROUP BY cmid,l.course,instance";
2b63df96 856
185cfb09 857 if (!$new = get_records_sql($sql)) {
858 $new = array(); // avoid warnings
859 }
2b63df96 860
185cfb09 861 // also get all forum tracking stuff ONCE.
862 $trackingforums = array();
863 foreach ($forums as $forum) {
864 if (forum_tp_can_track_forums($forum)) {
865 $trackingforums[$forum->id] = $forum;
866 }
867 }
2b63df96 868
185cfb09 869 if (count($trackingforums) > 0) {
870 $cutoffdate = isset($CFG->forum_oldpostdays) ? (time() - ($CFG->forum_oldpostdays*24*60*60)) : 0;
871 $sql = 'SELECT d.forum,d.course,COUNT(p.id) AS count '.
872 ' FROM '.$CFG->prefix.'forum_posts p '.
873 ' JOIN '.$CFG->prefix.'forum_discussions d ON p.discussion = d.id '.
874 ' LEFT JOIN '.$CFG->prefix.'forum_read r ON r.postid = p.id AND r.userid = '.$USER->id.' WHERE (';
d3553951 875 foreach ($trackingforums as $track) {
876 $sql .= '(d.forum = '.$track->id.' AND (d.groupid = -1 OR d.groupid = 0 OR d.groupid = '.get_current_group($track->course,false).')) OR ';
185cfb09 877 }
878 $sql = substr($sql,0,-3); // take off the last OR
879 $sql .= ') AND p.modified >= '.$cutoffdate.' AND r.id is NULL GROUP BY d.forum,d.course';
880
881 if (!$unread = get_records_sql($sql)) {
882 $unread = array();
883 }
884 } else {
885 $unread = array();
95d71ad3 886 }
185cfb09 887
9cba7a8c 888 if (empty($unread) and empty($new)) {
889 return;
890 }
891
892 $strforum = get_string('modulename','forum');
893 $strnumunread = get_string('overviewnumunread','forum');
894 $strnumpostssince = get_string('overviewnumpostssince','forum');
895
f8716988 896 foreach ($forums as $forum) {
185cfb09 897 $str = '';
f8716988 898 $count = 0;
185cfb09 899 $thisunread = 0;
f8716988 900 $showunread = false;
901 // either we have something from logs, or trackposts, or nothing.
902 if (array_key_exists($forum->id, $new) && !empty($new[$forum->id])) {
903 $count = $new[$forum->id]->count;
90558ec4 904 }
185cfb09 905 if (array_key_exists($forum->id,$unread)) {
906 $thisunread = $unread[$forum->id]->count;
f8716988 907 $showunread = true;
0d6b9d4f 908 }
185cfb09 909 if ($count > 0 || $thisunread > 0) {
e23800b7 910 $str .= '<div class="overview forum"><div class="name">'.$strforum.': <a title="'.$strforum.'" href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'">'.
911 $forum->name.'</a></div>';
912 $str .= '<div class="info">';
913 $str .= $count.' '.$strnumpostssince;
f8716988 914 if (!empty($showunread)) {
e23800b7 915 $str .= '<br />'.$thisunread .' '.$strnumunread;
f8716988 916 }
e23800b7 917 $str .= '</div></div>';
f8716988 918 }
2b63df96 919 if (!empty($str)) {
185cfb09 920 if (!array_key_exists($forum->course,$htmlarray)) {
921 $htmlarray[$forum->course] = array();
922 }
923 if (!array_key_exists('forum',$htmlarray[$forum->course])) {
924 $htmlarray[$forum->course]['forum'] = ''; // initialize, avoid warnings
925 }
926 $htmlarray[$forum->course]['forum'] .= $str;
927 }
2b63df96 928 }
0d6b9d4f 929}
930
1b5910c4 931function forum_print_recent_activity($course, $isteacher, $timestart) {
65b0e537 932/// Given a course and a date, prints a summary of all the new
cc3655a2 933/// messages posted in the course since that date
934
3d891989 935 global $CFG;
a8f4522d 936 $LIKE = sql_ilike();
caadf009 937
938 $heading = false;
939 $content = false;
940
8f7dc7f1 941 if (!$logs = get_records_select('log', 'time > \''.$timestart.'\' AND '.
942 'course = \''.$course->id.'\' AND '.
943 'module = \'forum\' AND '.
90eca94b 944 'action '.$LIKE.' \'add %\' ', 'time ASC')){
1b5910c4 945 return false;
946 }
947
8f7dc7f1 948 $strftimerecent = get_string('strftimerecent');
dcde9f02 949
10b63984 950 $mygroupid = mygroupid($course->id);
d05956ac 951 $groupmode = array(); /// To cache group modes
952
1b5910c4 953 foreach ($logs as $log) {
954 //Get post info, I'll need it later
ac1d9a22 955 if ($post = forum_get_post_from_log($log)) {
956 //Create a temp valid module structure (course,id)
957 $tempmod->course = $log->course;
958 $tempmod->id = $post->forum;
959 //Obtain the visible property from the instance
10b63984 960 $coursecontext = get_context_instance(CONTEXT_COURSE, $tempmod->course);
583b57b4 961 $modvisible = instance_is_visible('forum', $tempmod)
962 || has_capability('moodle/course:viewhiddenactivities', $coursecontext);
ac1d9a22 963 }
d05956ac 964
ac1d9a22 965 //Only if the post exists and mod is visible
966 if ($post && $modvisible) {
583b57b4 967
968 if (!isset($cm[$post->forum])) {
969 $cm[$post->forum] = get_coursemodule_from_instance('forum', $post->forum, $course->id);
ac1d9a22 970 }
583b57b4 971 $modcontext = get_context_instance(CONTEXT_MODULE, $cm[$post->forum]->id);
972
ac1d9a22 973 /// Check whether this is belongs to a discussion in a group that
974 /// should NOT be accessible to the current user
583b57b4 975 if (!has_capability('moodle/site:accessallgroups', $modcontext)
976 && $post->groupid != -1) { /// Open discussions have groupid -1
b91d6dcd 977
583b57b4 978 $groupmode[$post->forum] = groupmode($course, $cm[$post->forum]);
2b63df96 979
8f7dc7f1 980 if ($groupmode[$post->forum]) {
fa22fd5f 981 //hope i didn't break anything
982 if (!@in_array($mygroupid, $post->groupid))/*$mygroupid != $post->groupid*/{
ac1d9a22 983 continue;
984 }
1b5910c4 985 }
caadf009 986 }
ac1d9a22 987
988 if (! $heading) {
33e21153 989 print_headline(get_string('newforumposts', 'forum').':');
ac1d9a22 990 $heading = true;
991 $content = true;
992 }
993 $date = userdate($post->modified, $strftimerecent);
8f7dc7f1 994
995 $subjectclass = ($log->action == 'add discussion') ? ' bold' : '';
996
33e21153 997 echo '<div class="head">'.
a4f7aac1 998 '<div class="date">'.$date.'</div>'.
583b57b4 999 '<div class="name">'.fullname($post, has_capability('moodle/site:viewfullnames', $coursecontext)).'</div>'.
a4f7aac1 1000 '</div>';
1001 echo '<div class="info'.$subjectclass.'">';
8f7dc7f1 1002 echo '"<a href="'.$CFG->wwwroot.'/mod/forum/'.str_replace('&', '&amp;', $log->url).'">';
17dc3f3c 1003 $post->subject = break_up_long_words(format_string($post->subject,true));
8f7dc7f1 1004 echo $post->subject;
33e21153 1005 echo '</a>"</div>';
caadf009 1006 }
1007 }
1008 return $content;
1009}
1010
1011
1012function forum_grades($forumid) {
1013/// Must return an array of grades, indexed by user, and a max grade.
caadf009 1014
4db9d14d 1015 if (!$forum = get_record("forum", "id", $forumid)) {
1016 return false;
1017 }
1018 if (!$forum->assessed) {
1019 return false;
1020 }
d6bdd9d5 1021 $scalemenu = make_grades_menu($forum->scale);
02ebf404 1022
1023 $currentuser = 0;
1024 $ratingsuser = array();
1025
1f48942e 1026 if ($ratings = forum_get_user_grades($forumid)) {
02ebf404 1027 foreach ($ratings as $rating) { // Ordered by user
1028 if ($currentuser and $rating->userid != $currentuser) {
1029 if (!empty($ratingsuser)) {
d6bdd9d5 1030 if ($forum->scale < 0) {
1031 $return->grades[$currentuser] = forum_get_ratings_mean(0, $scalemenu, $ratingsuser);
1032 $return->grades[$currentuser] .= "<br />".forum_get_ratings_summary(0, $scalemenu, $ratingsuser);
1033 } else {
1034 $total = 0;
1035 $count = 0;
1036 foreach ($ratingsuser as $ra) {
1037 $total += $ra;
1038 $count ++;
1039 }
1040 $return->grades[$currentuser] = format_float($total/$count, 2);
1041 }
02ebf404 1042 } else {
1043 $return->grades[$currentuser] = "";
1044 }
1045 $ratingsuser = array();
caadf009 1046 }
02ebf404 1047 $ratingsuser[] = $rating->rating;
1048 $currentuser = $rating->userid;
caadf009 1049 }
02ebf404 1050 if (!empty($ratingsuser)) {
d6bdd9d5 1051 if ($forum->scale < 0) {
1052 $return->grades[$currentuser] = forum_get_ratings_mean(0, $scalemenu, $ratingsuser);
1053 $return->grades[$currentuser] .= "<br />".forum_get_ratings_summary(0, $scalemenu, $ratingsuser);
1054 } else {
1055 $total = 0;
1056 $count = 0;
1057 foreach ($ratingsuser as $ra) {
1058 $total += $ra;
1059 $count ++;
1060 }
1061 $return->grades[$currentuser] = format_float((float)$total/(float)$count, 2);
1062 }
02ebf404 1063 } else {
1064 $return->grades[$currentuser] = "";
caadf009 1065 }
1066 } else {
1067 $return->grades = array();
1068 }
1069
d6bdd9d5 1070 if ($forum->scale < 0) {
1071 $return->maxgrade = "";
1072 } else {
1073 $return->maxgrade = $forum->scale;
1074 }
caadf009 1075 return $return;
1076}
1077
05855091 1078function forum_get_participants($forumid) {
1079//Returns the users with data in one forum
65b0e537 1080//(users with records in forum_subscriptions, forum_posts and forum_ratings, students)
05855091 1081
1082 global $CFG;
1083
1084 //Get students from forum_subscriptions
95e72c12 1085 $st_subscriptions = get_records_sql("SELECT DISTINCT u.id, u.id
05855091 1086 FROM {$CFG->prefix}user u,
1087 {$CFG->prefix}forum_subscriptions s
1088 WHERE s.forum = '$forumid' and
65b0e537 1089 u.id = s.userid");
05855091 1090 //Get students from forum_posts
95e72c12 1091 $st_posts = get_records_sql("SELECT DISTINCT u.id, u.id
05855091 1092 FROM {$CFG->prefix}user u,
1093 {$CFG->prefix}forum_discussions d,
1094 {$CFG->prefix}forum_posts p
1095 WHERE d.forum = '$forumid' and
1096 p.discussion = d.id and
1097 u.id = p.userid");
1098
1099 //Get students from forum_ratings
95e72c12 1100 $st_ratings = get_records_sql("SELECT DISTINCT u.id, u.id
05855091 1101 FROM {$CFG->prefix}user u,
1102 {$CFG->prefix}forum_discussions d,
1103 {$CFG->prefix}forum_posts p,
1104 {$CFG->prefix}forum_ratings r
1105 WHERE d.forum = '$forumid' and
1106 p.discussion = d.id and
1107 r.post = p.id and
1108 u.id = r.userid");
1109
1110 //Add st_posts to st_subscriptions
1111 if ($st_posts) {
1112 foreach ($st_posts as $st_post) {
1113 $st_subscriptions[$st_post->id] = $st_post;
1114 }
1115 }
1116 //Add st_ratings to st_subscriptions
1117 if ($st_ratings) {
1118 foreach ($st_ratings as $st_rating) {
1119 $st_subscriptions[$st_rating->id] = $st_rating;
1120 }
1121 }
1122 //Return st_subscriptions array (it contains an array of unique users)
1123 return ($st_subscriptions);
1124}
caadf009 1125
0f1a97c2 1126function forum_scale_used ($forumid,$scaleid) {
1127//This function returns if a scale is being used by one forum
65b0e537 1128
0f1a97c2 1129 $return = false;
65b0e537 1130
0f1a97c2 1131 $rec = get_record("forum","id","$forumid","scale","-$scaleid");
65b0e537 1132
fa22fd5f 1133 if (!empty($rec) && !empty($scaleid)) {
0f1a97c2 1134 $return = true;
1135 }
65b0e537 1136
0f1a97c2 1137 return $return;
1138}
1139
9fa49e22 1140/// SQL FUNCTIONS ///////////////////////////////////////////////////////////
1141
1f48942e 1142function forum_get_post_full($postid) {
1143/// Gets a post with all info ready for forum_print_post
77efef3e 1144/// Most of these joins are just to get the forum id
1f48942e 1145 global $CFG;
1146
8fbdc992 1147 return get_record_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture
6572ab71 1148 FROM {$CFG->prefix}forum_posts p
1149 LEFT JOIN {$CFG->prefix}forum_discussions d ON p.discussion = d.id
6572ab71 1150 LEFT JOIN {$CFG->prefix}user u ON p.userid = u.id
1151 WHERE p.id = '$postid'");
1f48942e 1152}
1153
77efef3e 1154function forum_get_discussion_posts($discussion, $sort, $forumid) {
1f48942e 1155/// Gets posts with all info ready for forum_print_post
2b63df96 1156/// We pass forumid in because we always know it so no need to make a
77efef3e 1157/// complicated join to find it out.
1f48942e 1158 global $CFG;
1159
77efef3e 1160 return get_records_sql("SELECT p.*, $forumid AS forum, u.firstname, u.lastname, u.email, u.picture
10426cef 1161 FROM {$CFG->prefix}forum_posts p
10426cef 1162 LEFT JOIN {$CFG->prefix}user u ON p.userid = u.id
65b0e537 1163 WHERE p.discussion = $discussion
10426cef 1164 AND p.parent > 0 $sort");
1f48942e 1165}
1166
77efef3e 1167function forum_get_child_posts($parent, $forumid) {
1f48942e 1168/// Gets posts with all info ready for forum_print_post
2b63df96 1169/// We pass forumid in because we always know it so no need to make a
77efef3e 1170/// complicated join to find it out.
1f48942e 1171 global $CFG;
1172
77efef3e 1173 return get_records_sql("SELECT p.*, $forumid AS forum, u.firstname, u.lastname, u.email, u.picture
10426cef 1174 FROM {$CFG->prefix}forum_posts p
10426cef 1175 LEFT JOIN {$CFG->prefix}user u ON p.userid = u.id
65b0e537 1176 WHERE p.parent = '$parent'
1f48942e 1177 ORDER BY p.created ASC");
1178}
1179
42fb3c85 1180/**
1181 * An array of forum objects that the user is allowed to read/search through.
1182 * @param $userid
1183 * @param $courseid - if 0, we look for forums throughout the whole site.
1184 * @return array of forum objects, or false if no matches
1185 * Forum objects have the following attributes:
1186 * id, type, course, cmid, cmvisible, cmgroupmode, accessallgroups,
1187 * viewhiddentimedposts
1188 */
1189function forum_get_readable_forums($userid, $courseid=0) {
2b63df96 1190
d50704bf 1191 global $CFG, $USER;
2b63df96 1192
42fb3c85 1193 if (!$forummod = get_record('modules', 'name', 'forum')) {
1194 error('The forum module is not installed');
1195 }
2b63df96 1196
42fb3c85 1197 if ($courseid) {
1198 $courses = get_records('course', 'id', $courseid);
1199 } else {
6155150c 1200 /// If no course is specified, then the user can see SITE + his courses.
1201 /// And admins can see all courses, so pass the $doanything flag enabled
1202 $courses1 = get_records('course', 'id', SITEID);
1203 $courses2 = get_my_courses($userid, '', '*', true);
1204 $courses = array_merge($courses1, $courses2);
42fb3c85 1205 }
1206 if (!$courses) {
1207 return false;
1208 }
1209
1210 $readableforums = array();
2b63df96 1211
6527b5c2 1212 foreach ($courses as $course) {
1213
42fb3c85 1214 $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
2b63df96 1215
42fb3c85 1216 if (has_capability('moodle/course:viewhiddenactivities', $coursecontext)) {
1217 $selecthidden = ' AND cm.visible = 1';
1218 } else {
1219 $selecthidden = '';
1220 }
2b63df96 1221
0b9873f2 1222 $selectforums = "SELECT f.id AS id,
583b57b4 1223 f.name AS name,
42fb3c85 1224 f.type AS type,
1225 f.course AS course,
1226 cm.id AS cmid,
1227 cm.visible AS cmvisible,
1228 cm.groupmode AS cmgroupmode
f274fe07 1229 FROM {$CFG->prefix}course_modules cm,
1230 {$CFG->prefix}forum f
42fb3c85 1231 WHERE cm.instance = f.id
1232 AND cm.course = {$course->id}
1233 AND cm.module = {$forummod->id}
583b57b4 1234 $selecthidden
1235 ORDER BY f.name ASC";
2b63df96 1236
42fb3c85 1237 if ($forums = get_records_sql($selectforums)) {
2b63df96 1238
42fb3c85 1239 $group = user_group($course->id, $userid);
2b63df96 1240
42fb3c85 1241 foreach ($forums as $forum) {
1242 $forumcontext = get_context_instance(CONTEXT_MODULE, $forum->cmid);
2b63df96 1243
9222e721 1244 if (has_capability('mod/forum:viewdiscussion', $forumcontext)) {
d50704bf 1245
6527b5c2 1246 // Evaluate groupmode.
1247 $cm = new object;
1248 $cm->id = $forum->cmid;
1249 $cm->groupmode = $forum->cmgroupmode;
1250 $forum->cmgroupmode = groupmode($course, $cm);
1251
1252 if ($forum->cmgroupmode == SEPARATEGROUPS
1253 && !has_capability('moodle/site:accessallgroups', $forumcontext)) {
1254 $forum->accessallgroups = false;
1255 $forum->accessgroup = $group->id; // The user can only access
1256 // discussions for this group.
1257 } else {
1258 $forum->accessallgroups = true;
1259 }
1260
42fb3c85 1261 $forum->viewhiddentimedposts
1262 = has_capability('mod/forum:viewhiddentimedposts', $forumcontext);
2b63df96 1263
d50704bf 1264 if ($forum->type == 'qanda'
1265 && !has_capability('mod/forum:viewqandawithoutposting', $forumcontext)) {
1266
1267 // We need to check whether the user has posted in the qanda forum.
d50704bf 1268 $forum->onlydiscussions = array(); // Holds discussion ids for the discussions
1269 // the user is allowed to see in this forum.
2b63df96 1270
dcd8e589 1271 if ($discussionspostedin =
1272 forum_discussions_user_has_posted_in($forum->id, $USER->id)) {
1273 foreach ($discussionspostedin as $d) {
1274 array_push($forum->onlydiscussions, $d->id);
1275 }
d50704bf 1276 }
1277 }
42fb3c85 1278 array_push($readableforums, $forum);
1279 }
1280 }
1281 }
1282 } // End foreach $courses
2b63df96 1283
67875aa1 1284 //print_object($courses);
1285 //print_object($readableforums);
2b63df96 1286
42fb3c85 1287 return $readableforums;
1288}
1289
bbbf2d40 1290/**
1291 * Returns a list of posts found using an array of search terms.
42fb3c85 1292 * @param $searchterms - array of search terms, e.g. word +word -word
1293 * @param $courseid - if 0, we search through the whole site
bbbf2d40 1294 * @param $page
1295 * @param $recordsperpage=50
1296 * @param &$totalcount
bbbf2d40 1297 * @param $extrasql
42fb3c85 1298 * @return array of posts found
1299 */
2b63df96 1300function forum_search_posts($searchterms, $courseid=0, $limitfrom=0, $limitnum=50,
42fb3c85 1301 &$totalcount, $extrasql='') {
1302 global $CFG, $USER;
1303 require_once($CFG->libdir.'/searchlib.php');
1304
1305 $forums = forum_get_readable_forums($USER->id, $courseid);
2b63df96 1306
67875aa1 1307 if (count($forums) == 0) {
1308 return false;
1309 }
42fb3c85 1310
1311 for ($i=0; $i<count($forums); $i++) {
1312 if ($i == 0) {
1313 $selectdiscussion = " ((d.forum = {$forums[$i]->id}";
1314 } else {
1315 $selectdiscussion .= " OR (d.forum = {$forums[$i]->id}";
1316 }
1317 if (!empty($CFG->forum_enabletimedposts) && !$forums[$i]->viewhiddentimedposts) {
1318 $now = time();
1319 $selectdiscussion .= " AND ( d.userid = {$USER->id}
1320 OR ((d.timestart = 0 OR d.timestart <= $now)
1321 AND (d.timeend = 0 OR d.timeend > $now)) )";
1322 }
cac40c27 1323 if ($forums[$i]->type == 'qanda' && isset($forums[$i]->onlydiscussions)) {
d50704bf 1324 // This is a qanda forum.
1325 if (is_array($forums[$i]->onlydiscussions)) {
1326 // Show question posts as well as posts from discussions in
1327 // which the user has posted a reply.
1328 $onlydiscussions = implode(' OR d.id = ', $forums[$i]->onlydiscussions);
1329 $selectdiscussion .= " AND ((d.id = $onlydiscussions) OR p.parent = 0)";
1330 } else {
1331 // Show only the question posts.
1332 $selectdiscussion .= ' AND (p.parent = 0)';
1333 }
1334 }
42fb3c85 1335 if (!$forums[$i]->accessallgroups) {
1336 if (!empty($forums[$i]->accessgroup)) {
1337 $selectdiscussion .= " AND (d.groupid = {$forums[$i]->accessgroup}";
1338 $selectdiscussion .= ' OR d.groupid = -1)'; // -1 means open for all groups.
1339 } else {
1340 // User isn't in any group. Only search discussions that are
1341 // open to all groups.
1342 $selectdiscussion .= ' AND d.groupid = -1';
1343 }
1344 }
1345 $selectdiscussion .= ")\n";
1346 }
1347 $selectdiscussion .= ")";
1348
1349
a8f4522d 1350 // Some differences SQL
1351 $LIKE = sql_ilike();
1352 $NOTLIKE = 'NOT ' . $LIKE;
a4bad45c 1353 if ($CFG->dbfamily == 'postgres') {
42fb3c85 1354 $REGEXP = '~*';
1355 $NOTREGEXP = '!~*';
a8f4522d 1356 } else {
42fb3c85 1357 $REGEXP = 'REGEXP';
1358 $NOTREGEXP = 'NOT REGEXP';
1359 }
1360
1361 $messagesearch = '';
1362 $searchstring = '';
2b63df96 1363
42fb3c85 1364 // Need to concat these back together for parser to work.
1365 foreach($searchterms as $searchterm){
1366 if ($searchstring != '') {
1367 $searchstring .= ' ';
1368 }
1369 $searchstring .= $searchterm;
1370 }
1371
1372 // We need to allow quoted strings for the search. The quotes *should* be stripped
1373 // by the parser, but this should be examined carefully for security implications.
1374 $searchstring = str_replace("\\\"","\"",$searchstring);
1375 $parser = new search_parser();
1376 $lexer = new search_lexer($parser);
1377
1378 if ($lexer->parse($searchstring)) {
1379 $parsearray = $parser->get_parsed_array();
1380 $messagesearch = search_generate_SQL($parsearray, 'p.message', 'p.subject',
1381 'p.userid', 'u.id', 'u.firstname',
1382 'u.lastname', 'p.modified', 'd.forum');
1383 }
1384
1385 $fromsql = "{$CFG->prefix}forum_posts p,
1386 {$CFG->prefix}forum_discussions d,
1387 {$CFG->prefix}user u";
1388
1389 $selectsql = " $messagesearch
1390 AND p.discussion = d.id
1391 AND p.userid = u.id
1392 AND $selectdiscussion
1393 $extrasql";
1394
1395 $countsql = "SELECT COUNT(*)
1396 FROM $fromsql
1397 WHERE $selectsql";
1398
7f094149 1399 $searchsql = "SELECT p.*,
42fb3c85 1400 d.forum,
1401 u.firstname,
1402 u.lastname,
1403 u.email,
1404 u.picture
1405 FROM $fromsql
1406 WHERE $selectsql
1407 ORDER BY p.modified DESC";
1408
b1342e18 1409 $totalcount = count_records_sql($countsql);
d50704bf 1410
67875aa1 1411 return get_records_sql($searchsql, $limitfrom, $limitnum);
42fb3c85 1412}
1413
9fa49e22 1414function forum_get_ratings($postid, $sort="u.firstname ASC") {
1415/// Returns a list of ratings for a particular post - sorted.
1416 global $CFG;
65b0e537 1417 return get_records_sql("SELECT u.*, r.rating, r.time
1418 FROM {$CFG->prefix}forum_ratings r,
9fa49e22 1419 {$CFG->prefix}user u
65b0e537 1420 WHERE r.post = '$postid'
1421 AND r.userid = u.id
9fa49e22 1422 ORDER BY $sort");
1423}
1424
3ecca1ee 1425function forum_get_unmailed_posts($starttime, $endtime) {
1f48942e 1426/// Returns a list of all new posts that have not been mailed yet
1427 global $CFG;
fbc21e82 1428 $now = time();
65b0e537 1429 return get_records_sql("SELECT p.*, d.course
1430 FROM {$CFG->prefix}forum_posts p,
1f48942e 1431 {$CFG->prefix}forum_discussions d
65b0e537 1432 WHERE p.mailed = 0
b12d055a 1433 AND (p.created >= '$starttime' OR d.timestart > 0)
41547057 1434 AND (p.created < '$endtime' OR p.mailnow = 1)
c274b0e0 1435 AND p.discussion = d.id
fbc21e82 1436 AND ((d.timestart = 0 OR d.timestart <= '$now')
1437 AND (d.timeend = 0 OR d.timeend > '$now'))
0fcac008 1438 ORDER BY p.modified ASC");
1f48942e 1439}
1440
3ecca1ee 1441function forum_mark_old_posts_as_mailed($endtime) {
1442/// Marks posts before a certain time as being mailed already
1443 global $CFG;
0f620d4b 1444/// Find out posts those are not showing immediately so we can exclude them
1445 $now = time();
1446 $delayed_posts = get_records_sql("SELECT p.id, p.discussion
1447 FROM {$CFG->prefix}forum_posts p,
1448 {$CFG->prefix}forum_discussions d
1449 WHERE p.mailed = 0
1450 AND p.discussion = d.id
1451 AND d.timestart > '$now'");
1452 $delayed_ids = array();
1453 if ($delayed_posts) {
1454 foreach ($delayed_posts as $post) {
1455 $delayed_ids[] = $post->id;
1456 }
1457 } else {
1458 $delayed_ids[] = 0;
1459 }
c274b0e0 1460 return execute_sql("UPDATE {$CFG->prefix}forum_posts
1461 SET mailed = '1'
9ed7d7e1 1462 WHERE id NOT IN (".implode(',',$delayed_ids).")
1463 AND (created < '$endtime' OR mailnow = 1)
1464 AND mailed ='0'", false);
3ecca1ee 1465}
1466
1f48942e 1467function forum_get_user_posts($forumid, $userid) {
1468/// Get all the posts for a user in a forum suitable for forum_print_post
1469 global $CFG;
1470
77efef3e 1471 return get_records_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture
65b0e537 1472 FROM {$CFG->prefix}forum f,
1473 {$CFG->prefix}forum_discussions d,
1474 {$CFG->prefix}forum_posts p,
1475 {$CFG->prefix}user u
1476 WHERE f.id = '$forumid'
1477 AND d.forum = f.id
1f48942e 1478 AND p.discussion = d.id
65b0e537 1479 AND p.userid = '$userid'
ebc3bd2b 1480 AND p.userid = u.id
1f48942e 1481 ORDER BY p.modified ASC");
1482}
1483
1484function forum_get_post_from_log($log) {
1485/// Given a log entry, return the forum post details for it.
1486 global $CFG;
1487
1488 if ($log->action == "add post") {
1489
2b63df96 1490 return get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
8f7dc7f1 1491 u.firstname, u.lastname, u.email, u.picture
65b0e537 1492 FROM {$CFG->prefix}forum_discussions d,
1493 {$CFG->prefix}forum_posts p,
8f7dc7f1 1494 {$CFG->prefix}forum f,
65b0e537 1495 {$CFG->prefix}user u
1496 WHERE p.id = '$log->info'
1497 AND d.id = p.discussion
1498 AND p.userid = u.id
8f7dc7f1 1499 AND u.deleted <> '1'
1500 AND f.id = d.forum");
1f48942e 1501
1502
1503 } else if ($log->action == "add discussion") {
1504
2b63df96 1505 return get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
8f7dc7f1 1506 u.firstname, u.lastname, u.email, u.picture
65b0e537 1507 FROM {$CFG->prefix}forum_discussions d,
1508 {$CFG->prefix}forum_posts p,
8f7dc7f1 1509 {$CFG->prefix}forum f,
65b0e537 1510 {$CFG->prefix}user u
1511 WHERE d.id = '$log->info'
1512 AND d.firstpost = p.id
1513 AND p.userid = u.id
8f7dc7f1 1514 AND u.deleted <> '1'
1515 AND f.id = d.forum");
1f48942e 1516 }
1517 return NULL;
1518}
1519
d05956ac 1520function forum_get_firstpost_from_discussion($discussionid) {
1521/// Given a discussion id, return the first post from the discussion
1522 global $CFG;
1523
1524 return get_record_sql("SELECT p.*
65b0e537 1525 FROM {$CFG->prefix}forum_discussions d,
d05956ac 1526 {$CFG->prefix}forum_posts p
65b0e537 1527 WHERE d.id = '$discussionid'
d05956ac 1528 AND d.firstpost = p.id ");
1529}
1530
1f48942e 1531
1532function forum_get_user_grades($forumid) {
1533/// Get all user grades for a forum
1534 global $CFG;
1535
ebc3bd2b 1536 return get_records_sql("SELECT r.id, p.userid, r.rating
65b0e537 1537 FROM {$CFG->prefix}forum_discussions d,
1538 {$CFG->prefix}forum_posts p,
1f48942e 1539 {$CFG->prefix}forum_ratings r
65b0e537 1540 WHERE d.forum = '$forumid'
1f48942e 1541 AND p.discussion = d.id
02ebf404 1542 AND r.post = p.id
1543 ORDER by p.userid ");
1f48942e 1544}
1545
1546
a48e8c4b 1547function forum_count_discussion_replies($forum='0', $course='0', $user='0') {
1548// Returns an array of counts of replies to each discussion (optionally in one forum or course and/or user)
1f48942e 1549 global $CFG;
1550
a48e8c4b 1551 $forumselect = $courseselect = $userselect = '';
1552
1f48942e 1553 if ($forum) {
1554 $forumselect = " AND d.forum = '$forum'";
a48e8c4b 1555 }
1556 if ($course) {
1557 $courseselect = " AND d.course = '$course'";
1558 }
1559 if ($user) {
1560 $userselect = " AND d.userid = '$user'";
1f48942e 1561 }
3599e487 1562 return get_records_sql("SELECT p.discussion, (count(*)) as replies, max(p.id) as lastpostid
65b0e537 1563 FROM {$CFG->prefix}forum_posts p,
1f48942e 1564 {$CFG->prefix}forum_discussions d
a48e8c4b 1565 WHERE p.parent > 0 $forumselect $courseselect $userselect
1c887009 1566 AND p.discussion = d.id
1f48942e 1567 GROUP BY p.discussion");
1568}
1569
1570function forum_count_unrated_posts($discussionid, $userid) {
1571// How many unrated posts are in the given discussion for a given user?
1572 global $CFG;
1573 if ($posts = get_record_sql("SELECT count(*) as num
1574 FROM {$CFG->prefix}forum_posts
65b0e537 1575 WHERE parent > 0
1576 AND discussion = '$discussionid'
ebc3bd2b 1577 AND userid <> '$userid' ")) {
1f48942e 1578
65b0e537 1579 if ($rated = get_record_sql("SELECT count(*) as num
1580 FROM {$CFG->prefix}forum_posts p,
1f48942e 1581 {$CFG->prefix}forum_ratings r
1582 WHERE p.discussion = '$discussionid'
65b0e537 1583 AND p.id = r.post
ebc3bd2b 1584 AND r.userid = '$userid'")) {
1f48942e 1585 $difference = $posts->num - $rated->num;
1586 if ($difference > 0) {
1587 return $difference;
1588 } else {
1589 return 0; // Just in case there was a counting error
1590 }
1591 } else {
1592 return $posts->num;
1593 }
1594 } else {
1595 return 0;
1596 }
1597}
1598
65b0e537 1599function forum_get_discussions($forum="0", $forumsort="d.timemodified DESC",
13597d01 1600 $user=0, $fullpost=true, $visiblegroups=-1, $limit=0, $userlastmodified=false) {
1f48942e 1601/// Get all discussions in a forum
fbc21e82 1602 global $CFG, $USER;
0fcac008 1603
3d284127 1604 $timelimit = '';
1605
1606 if (!empty($CFG->forum_enabletimedposts)) {
2b63df96 1607
7613e6d7 1608 if (!$cm = get_coursemodule_from_instance('forum', $forum)) {
1609 error('Course Module ID was incorrect');
1610 }
1611 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2b63df96 1612
0468976c 1613 if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
3d284127 1614 $now = time();
1615 $timelimit = " AND ((d.timestart = 0 OR d.timestart <= '$now') AND (d.timeend = 0 OR d.timeend > '$now')";
1616 if (!empty($USER->id)) {
1617 $timelimit .= " OR d.userid = '$USER->id'";
1618 }
1619 $timelimit .= ')';
fbc21e82 1620 }
fbc21e82 1621 }
1f48942e 1622
1623 if ($user) {
1624 $userselect = " AND u.id = '$user' ";
1625 } else {
1626 $userselect = "";
1627 }
2862b309 1628
9eabd190 1629 $limitfrom = 0;
1630 $limitnum = 0;
90ec387a 1631 if ($limit) {
9eabd190 1632 $limitnum = $limit;
90ec387a 1633 }
8f0cd6ef 1634
2862b309 1635 if ($visiblegroups == -1) {
02509fe6 1636 $groupselect = "";
2862b309 1637 } else {
1638 $groupselect = " AND (d.groupid = '$visiblegroups' OR d.groupid = '-1') ";
02509fe6 1639 }
2862b309 1640
29507631 1641 if (empty($forumsort)) {
1642 $forumsort = "d.timemodified DESC";
1643 }
2ab968e9 1644 if (empty($fullpost)) {
b879effb 1645 $postdata = "p.id,p.subject,p.modified,p.discussion,p.userid";
2ab968e9 1646 } else {
1647 $postdata = "p.*";
1648 }
9197e147 1649
13597d01 1650 if (empty($userlastmodified)) { // We don't need to know this
1651 $umfields = '';
1652 $umtable = '';
13597d01 1653 } else {
096de9ad 1654 $umfields = ', um.firstname AS umfirstname, um.lastname AS umlastname';
cfdc10e6 1655 $umtable = ' LEFT JOIN '.$CFG->prefix.'user um on (d.usermodified = um.id)';
13597d01 1656 }
1657
80d3523e 1658 //TODO: there must be a nice way to do this that keeps both postgres and mysql 3.2x happy but I can't find it right now.
a4bad45c 1659 if ($CFG->dbfamily == 'postgres' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'oracle') {
80d3523e 1660 return get_records_sql("SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid,
13597d01 1661 u.firstname, u.lastname, u.email, u.picture $umfields
93d58b30 1662 FROM {$CFG->prefix}forum_discussions d
1663 JOIN {$CFG->prefix}forum_posts p ON p.discussion = d.id
1664 JOIN {$CFG->prefix}user u ON p.userid = u.id
13597d01 1665 $umtable
65b0e537 1666 WHERE d.forum = '$forum'
65b0e537 1667 AND p.parent = 0
2b63df96 1668 $timelimit $groupselect $userselect
9eabd190 1669 ORDER BY $forumsort", $limitfrom, $limitnum);
a4bad45c 1670 } else { // MySQL query. TODO: Check if this is needed (MySQL 4.1 should work with the above query)
80d3523e 1671 return get_records_sql("SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid,
1672 u.firstname, u.lastname, u.email, u.picture $umfields
fd6590a9 1673 FROM ({$CFG->prefix}forum_posts p,
b73b9d81 1674 {$CFG->prefix}user u,
fd6590a9 1675 {$CFG->prefix}forum_discussions d)
80d3523e 1676 $umtable
1677 WHERE d.forum = '$forum'
1678 AND p.discussion = d.id
1679 AND p.parent = 0
80329e02 1680 AND p.userid = u.id $timelimit $groupselect $userselect
9eabd190 1681 ORDER BY $forumsort", $limitfrom, $limitnum);
80d3523e 1682 }
1f48942e 1683}
1684
1685
1686
b656e2a9 1687function forum_get_user_discussions($courseid, $userid, $groupid=0) {
1688/// Get all discussions started by a particular user in a course (or group)
4f321bdb 1689/// This function no longer used ...
1f48942e 1690 global $CFG;
1691
b656e2a9 1692 if ($groupid) {
1693 $groupselect = " AND d.groupid = '$groupid' ";
1694 } else {
1695 $groupselect = "";
1696 }
1697
2862b309 1698 return get_records_sql("SELECT p.*, d.groupid, u.firstname, u.lastname, u.email, u.picture,
ebc3bd2b 1699 f.type as forumtype, f.name as forumname, f.id as forumid
65b0e537 1700 FROM {$CFG->prefix}forum_discussions d,
1701 {$CFG->prefix}forum_posts p,
1702 {$CFG->prefix}user u,
1f48942e 1703 {$CFG->prefix}forum f
65b0e537 1704 WHERE d.course = '$courseid'
1705 AND p.discussion = d.id
1706 AND p.parent = 0
1707 AND p.userid = u.id
1708 AND u.id = '$userid'
b656e2a9 1709 AND d.forum = f.id $groupselect
b8bf90c5 1710 ORDER BY p.created DESC");
1f48942e 1711}
1712
669f2499 1713function forum_subscribed_users($course, $forum, $groupid=0, $cache=false) {
1f48942e 1714/// Returns list of user objects that are subscribed to this forum
1715 global $CFG;
1716
669f2499 1717 static $resultscache = array();
1718
1719 if ($cache && isset($resultscache[$forum->id][$groupid])) {
1720 return $resultscache[$forum->id][$groupid];
1721 }
1722
6673d7bd 1723 if ($groupid) {
e25cb710 1724 $grouptables = ', '. groups_members_from_sql();
1725 $groupselect = 'AND'.groups_members_where_sql($groupid, 'u.id');
6673d7bd 1726 } else {
669f2499 1727 $grouptables = '';
1728 $groupselect = '';
6673d7bd 1729 }
1730
709f0ec8 1731 if (forum_is_forcesubscribed($forum->id)) {
669f2499 1732 $results = get_course_users($course->id); // Otherwise get everyone in the course
1733 } else {
1734 $results = get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat, u.maildigest, u.emailstop,
9152fc99 1735 u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.timezone, u.theme, u.lang, u.trackforums
65b0e537 1736 FROM {$CFG->prefix}user u,
6673d7bd 1737 {$CFG->prefix}forum_subscriptions s $grouptables
1f48942e 1738 WHERE s.forum = '$forum->id'
65b0e537 1739 AND s.userid = u.id
6673d7bd 1740 AND u.deleted <> 1 $groupselect
7c81b6e2 1741 ORDER BY u.email ASC");
669f2499 1742 }
b725b819 1743 // Guest user should never be subscribed to a forum.
1744 if ($guest = guest_user()) {
1745 unset($results[$guest->id]);
1746 }
669f2499 1747
1748 if ($cache) {
1749 $resultscache[$forum->id][$groupid] = $results;
1750 }
1751
1752 return $results;
1f48942e 1753}
9fa49e22 1754
067675c0 1755
1756
caadf009 1757/// OTHER FUNCTIONS ///////////////////////////////////////////////////////////
f93f848a 1758
1759
11b0c469 1760function forum_get_course_forum($courseid, $type) {
1761// How to set up special 1-per-course forums
a6fcdf98 1762 global $CFG;
1763
29cbd93a 1764 if ($forums = get_records_select("forum", "course = '$courseid' AND type = '$type'", "id ASC")) {
65b0e537 1765 // There should always only be ONE, but with the right combination of
29cbd93a 1766 // errors there might be more. In this case, just return the oldest one (lowest ID).
1767 foreach ($forums as $forum) {
1768 return $forum; // ie the first one
11b0c469 1769 }
8daaf761 1770 }
e6874d9f 1771
8daaf761 1772 // Doesn't exist, so create one now.
1773 $forum->course = $courseid;
1774 $forum->type = "$type";
1775 switch ($forum->type) {
1776 case "news":
65a3ef30 1777 $forum->name = addslashes(get_string("namenews", "forum"));
1778 $forum->intro = addslashes(get_string("intronews", "forum"));
906fef94 1779 $forum->forcesubscribe = FORUM_FORCESUBSCRIBE;
8daaf761 1780 $forum->assessed = 0;
709f0ec8 1781 if ($courseid == SITEID) {
1782 $forum->name = get_string("sitenews");
1783 $forum->forcesubscribe = 0;
8f0cd6ef 1784 }
8daaf761 1785 break;
1786 case "social":
65a3ef30 1787 $forum->name = addslashes(get_string("namesocial", "forum"));
1788 $forum->intro = addslashes(get_string("introsocial", "forum"));
8daaf761 1789 $forum->assessed = 0;
1790 $forum->forcesubscribe = 0;
1791 break;
8daaf761 1792 default:
1793 notify("That forum type doesn't exist!");
1794 return false;
1795 break;
1796 }
1797
1798 $forum->timemodified = time();
1799 $forum->id = insert_record("forum", $forum);
1800
e1b5643f 1801 if (! $module = get_record("modules", "name", "forum")) {
1802 notify("Could not find forum module!!");
1803 return false;
82aa0e8d 1804 }
e1b5643f 1805 $mod->course = $courseid;
1806 $mod->module = $module->id;
1807 $mod->instance = $forum->id;
1808 $mod->section = 0;
1809 if (! $mod->coursemodule = add_course_module($mod) ) { // assumes course/lib.php is loaded
33e21153 1810 notify("Could not add a new course module to the course '$course->fullname'");
e1b5643f 1811 return false;
1812 }
1813 if (! $sectionid = add_mod_to_section($mod) ) { // assumes course/lib.php is loaded
1814 notify("Could not add the new course module to that section");
1815 return false;
1816 }
1817 if (! set_field("course_modules", "section", $sectionid, "id", $mod->coursemodule)) {
1818 notify("Could not update the course module with the correct section");
1819 return false;
1820 }
1821 include_once("$CFG->dirroot/course/lib.php");
1822 rebuild_course_cache($courseid);
65b0e537 1823
8daaf761 1824 return get_record("forum", "id", "$forum->id");
82aa0e8d 1825}
1826
f93f848a 1827
65b0e537 1828function forum_make_mail_post(&$post, $user, $touser, $course,
11b0c469 1829 $ownpost=false, $reply=false, $link=false, $rate=false, $footer="") {
2b63df96 1830
ee8e0008 1831 // Given the data about a posting, builds up the HTML to display it and
1832 // returns the HTML in a string. This is designed for sending via HTML email.
501cdbd8 1833
15f81ee3 1834 global $CFG, $USER;
501cdbd8 1835
0d851f90 1836 static $formattedtext; // Cached version of formatted text for a post
1837 static $formattedtextid; // The ID number of the post
1838
ee8e0008 1839 $post->forum = get_field('forum_discussions', 'forum', 'id', $post->discussion);
2b63df96 1840
ee8e0008 1841 if (!$cm = get_coursemodule_from_instance('forum', $post->forum)) {
2a692058 1842 mtrace('Course Module ID was incorrect');
7613e6d7 1843 }
1844 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
1845
1846
0d851f90 1847 if (empty($formattedtextid) or $formattedtextid != $post->id) { // Recalculate the formatting
326ce3c4 1848 $options = new Object;
1849 $options->para = true;
f2b5d7e3 1850 $formattedtext = format_text(trusttext_strip($post->message), $post->format, $options, $course->id);
0d851f90 1851 $formattedtextid = $post->id;
1852 }
1853
add3201e 1854 $output = '<table border="0" cellpadding="3" cellspacing="0" class="forumpost">';
501cdbd8 1855
add3201e 1856 $output .= '<tr class="header"><td width="35" valign="top" class="picture left">';
501cdbd8 1857 $output .= print_user_picture($user->id, $course->id, $user->picture, false, true);
add3201e 1858 $output .= '</td>';
501cdbd8 1859
1860 if ($post->parent) {
add3201e 1861 $output .= '<td class="topic">';
501cdbd8 1862 } else {
add3201e 1863 $output .= '<td class="topic starter">';
501cdbd8 1864 }
add3201e 1865 $output .= '<div class="subject">'.format_string($post->subject).'</div>';
1b26d5e7 1866
15f81ee3 1867 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $modcontext));
add3201e 1868 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
1869 $by->date = userdate($post->modified, '', $touser->timezone);
1870 $output .= '<div class="author">'.get_string('bynameondate', 'forum', $by).'</div>';
1871
1872 $output .= '</td></tr>';
1873
7b54f563 1874 $output .= '<tr><td class="left side" valign="top">';
add3201e 1875 if ($group = user_group($course->id, $user->id)) {
f393f545 1876 $output .= print_group_picture($group, $course->id, false, true, true);
add3201e 1877 } else {
1878 $output .= '&nbsp;';
1879 }
1b26d5e7 1880
add3201e 1881 $output .= '</td><td class="content">';
501cdbd8 1882
7f6689e4 1883 if ($post->attachment) {
1884 $post->course = $course->id;
add3201e 1885 $output .= '<div class="attachments">';
1886 $output .= forum_print_attachments($post, 'html');
72d497d4 1887 $output .= "</div>";
7f6689e4 1888 }
1889
0d851f90 1890 $output .= $formattedtext;
501cdbd8 1891
add3201e 1892/// Commands
add3201e 1893 $commands = array();
501cdbd8 1894
2e2e71a8 1895 if ($post->parent) {
add3201e 1896 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
1897 $post->discussion.'&amp;parent='.$post->parent.'">'.get_string('parent', 'forum').'</a>';
2e2e71a8 1898 }
ce45515e 1899
add3201e 1900 if ($reply) {
1901 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.
1902 get_string('reply', 'forum').'</a>';
501cdbd8 1903 }
1904
add3201e 1905 $output .= '<div class="commands">';
1906 $output .= implode(' | ', $commands);
1907 $output .= '</div>';
1908
add3201e 1909/// Context link to post if required
501cdbd8 1910 if ($link) {
add3201e 1911 $output .= '<div class="link">';
0be4d8bf 1912 $output .= '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#p'.$post->id.'">'.
2b63df96 1913 get_string('postincontext', 'forum').'</a>';
add3201e 1914 $output .= '</div>';
501cdbd8 1915 }
add3201e 1916
501cdbd8 1917 if ($footer) {
add3201e 1918 $output .= '<div class="footer">'.$footer.'</div>';
501cdbd8 1919 }
add3201e 1920 $output .= '</td></tr></table>'."\n\n";
1921
501cdbd8 1922 return $output;
1923}
1924
1925
65b0e537 1926function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link=false,
f37da850 1927 $ratings=NULL, $footer="", $highlight="", $post_read=-99) {
74f5d1e3 1928
098d27d4 1929 global $USER, $CFG, $SESSION;
501cdbd8 1930
951e1073 1931 static $stredit, $strdelete, $strreply, $strparent, $strprune;
1932 static $strpruneheading, $threadedmode;
77efef3e 1933 static $strmarkread, $strmarkunread, $istracked;
f37da850 1934
951e1073 1935
87ca0adf 1936 $discussion = get_record('forum_discussions', 'id', $post->discussion);
951e1073 1937 if (!$cm = get_coursemodule_from_instance('forum', $discussion->forum)) {
1938 error('Course Module ID was incorrect');
1939 }
1940 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
1941
1942
098d27d4 1943 if (!forum_user_can_see_post($post->forum,$post->discussion,$post)) {
1944 if (empty($SESSION->forum_search)) {
1945 // just viewing, return
1946 return;
2b63df96 1947 }
0be4d8bf 1948 echo '<a id="p'.$post->id.'"></a>';
098d27d4 1949 echo '<table cellspacing="0" class="forumpost">';
1950 echo '<tr class="header"><td class="picture left">';
1951 // print_user_picture($post->userid, $courseid, $post->picture);
1952 echo '</td>';
1953 if ($post->parent) {
1954 echo '<td class="topic">';
1955 } else {
1956 echo '<td class="topic starter">';
1957 }
1958 echo '<div class="subject">'.get_string('forumsubjecthidden','forum').'</div>';
1959 echo '<div class="author">';
1960 print_string('forumauthorhidden','forum');
1961 echo '</div></td></tr>';
2b63df96 1962
098d27d4 1963 echo '<tr><td class="left side">';
1964 echo '&nbsp;';
2b63df96 1965
098d27d4 1966 /// Actual content
2b63df96 1967
098d27d4 1968 echo '</td><td class="content">'."\n";
1969 echo get_string('forumbodyhidden','forum');
1970 echo '</td></tr></table>';
1971 return;
1972 }
1973
2e2e71a8 1974 if (empty($stredit)) {
359f2758 1975 $stredit = get_string('edit', 'forum');
1976 $strdelete = get_string('delete', 'forum');
1977 $strreply = get_string('reply', 'forum');
1978 $strparent = get_string('parent', 'forum');
1979 $strpruneheading = get_string('pruneheading', 'forum');
d494dd83 1980 $strprune = get_string('prune', 'forum');
2e2e71a8 1981 $threadedmode = (!empty($USER->mode) and ($USER->mode == FORUM_MODE_THREADED));
f37da850 1982 $strmarkread = get_string('markread', 'forum');
1983 $strmarkunread = get_string('markunread', 'forum');
77efef3e 1984
1985 if (!empty($post->forum)) {
2b63df96 1986 $istracked = (forum_tp_can_track_forums($post->forum) &&
77efef3e 1987 forum_tp_is_tracked($post->forum));
1988 } else {
1989 $istracked = false;
1990 }
f37da850 1991 }
1992
eaf50aef 1993 if ($istracked) {
f37da850 1994 if ($post_read == -99) { // If we don't know yet...
489de4ae 1995 /// The front page can display a news item post to non-logged in users. This should
1996 /// always appear as 'read'.
1997 $post_read = empty($USER) || forum_tp_is_post_read($USER->id, $post);
f37da850 1998 }
1999 if ($post_read) {
2000 $read_style = ' read';
2001 } else {
2002 $read_style = ' unread';
2003 echo '<a name="unread"></a>';
2004 }
2005 } else {
2006 $read_style = '';
2e2e71a8 2007 }
2008
0be4d8bf 2009 echo '<a id="p'.$post->id.'"></a>';
33200577 2010 echo '<table cellspacing="0" class="forumpost'.$read_style.'">';
501cdbd8 2011
d3583b41 2012 echo '<tr class="header"><td class="picture left">';
501cdbd8 2013 print_user_picture($post->userid, $courseid, $post->picture);
d3583b41 2014 echo '</td>';
501cdbd8 2015
2016 if ($post->parent) {
d3583b41 2017 echo '<td class="topic">';
501cdbd8 2018 } else {
d3583b41 2019 echo '<td class="topic starter">';
501cdbd8 2020 }
83ec9098 2021
47c9c8f5 2022 echo '<div class="subject">'.format_string($post->subject).'</div>';
e3ff14ca 2023
d3583b41 2024 echo '<div class="author">';
951e1073 2025 $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
d3583b41 2026 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
2027 $post->userid.'&amp;course='.$courseid.'">'.$fullname.'</a>';
d62413e8 2028 $by->date = userdate($post->modified);
d3583b41 2029 print_string('bynameondate', 'forum', $by);
2030 echo '</div></td></tr>';
1b26d5e7 2031
d3583b41 2032 echo '<tr><td class="left side">';
507407a7 2033 if ($group = user_group($courseid, $post->userid)) {
a4fbb0b2 2034 print_group_picture($group, $courseid, false, false, true);
507407a7 2035 } else {
d3583b41 2036 echo '&nbsp;';
507407a7 2037 }
d3583b41 2038
2039/// Actual content
2040
2041 echo '</td><td class="content">'."\n";
501cdbd8 2042
7f6689e4 2043 if ($post->attachment) {
2044 $post->course = $courseid;
d3583b41 2045 $post->forum = get_field('forum_discussions', 'forum', 'id', $post->discussion);
2046 echo '<div class="attachments">';
72d497d4 2047 $attachedimages = forum_print_attachments($post);
d3583b41 2048 echo '</div>';
e9c2dc1f 2049 } else {
d3583b41 2050 $attachedimages = '';
7f6689e4 2051 }
2052
d3583b41 2053
326ce3c4 2054 $options = new Object;
2055 $options->para = false;
f2b5d7e3 2056 $options->trusttext = true;
5be7800c 2057 if ($link and (strlen(strip_tags($post->message)) > $CFG->forum_longpost)) {
aa153f29 2058 // Print shortened version
326ce3c4 2059 echo format_text(forum_shorten_post($post->message), $post->format, $options, $courseid);
c585fa17 2060 $numwords = count_words(strip_tags($post->message));
d3583b41 2061 echo '<p><a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
2062 echo get_string('readtherest', 'forum');
2063 echo '</a> ('.get_string('numwords', '', $numwords).')...</p>';
501cdbd8 2064 } else {
aa153f29 2065 // Print whole message
88438a58 2066 if ($highlight) {
326ce3c4 2067 echo highlight($highlight, format_text($post->message, $post->format, $options, $courseid));
88438a58 2068 } else {
326ce3c4 2069 echo format_text($post->message, $post->format, $options, $courseid);
88438a58 2070 }
65b0e537 2071 echo $attachedimages;
501cdbd8 2072 }
2073
d3583b41 2074
2075/// Commands
2076
359f2758 2077 $commands = array();
501cdbd8 2078
eaf50aef 2079 if ($istracked) {
489de4ae 2080 /// SPECIAL CASE: The front page can display a news item post to non-logged in users.
2081 /// Don't display the mark read / unread controls in this case.
2082 if ($CFG->forum_usermarksread && !empty($USER)) {
f37da850 2083 if ($post_read) {
2084 $mcmd = '&amp;mark=unread&amp;postid='.$post->id;
2085 $mtxt = $strmarkunread;
2086 } else {
2087 $mcmd = '&amp;mark=read&amp;postid='.$post->id;
2088 $mtxt = $strmarkread;
2089 }
2090 if ($threadedmode) {
d3583b41 2091 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2092 $post->discussion.'&amp;parent='.$post->id.$mcmd.'">'.$mtxt.'</a>';
f37da850 2093 } else {
d3583b41 2094 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
0be4d8bf 2095 $post->discussion.$mcmd.'#p'.$post->id.'">'.$mtxt.'</a>';
f37da850 2096 }
2097 }
2098 }
2099
2e2e71a8 2100 if ($post->parent) {
2101 if ($threadedmode) {
d3583b41 2102 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2103 $post->discussion.'&amp;parent='.$post->parent.'">'.$strparent.'</a>';
2e2e71a8 2104 } else {
d3583b41 2105 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
0be4d8bf 2106 $post->discussion.'#p'.$post->parent.'">'.$strparent.'</a>';
2e2e71a8 2107 }
2108 }
2109
66035aaf 2110 $forumtype = get_field('forum', 'type', 'id', $post->forum);
2b63df96 2111
501cdbd8 2112 $age = time() - $post->created;
fbc21e82 2113 /// Hack for allow to edit news posts those are not displayed yet until they are displayed
2114 if (!$post->parent
66035aaf 2115 && $forumtype == 'news'
fbc21e82 2116 && get_field_sql("SELECT id FROM {$CFG->prefix}forum_discussions WHERE id = $post->discussion AND timestart > ".time())) {
2117 $age = 0;
2118 }
951e1073 2119 $editanypost = has_capability('mod/forum:editanypost', $modcontext);
9fbccd39 2120
6e372b25 2121
2122
a4ea3ef3 2123 if ($ownpost or $editanypost) {
951e1073 2124 if (($age < $CFG->maxeditingtime) or $editanypost) {
d3583b41 2125 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?edit='.$post->id.'">'.$stredit.'</a>';
501cdbd8 2126 }
64eacd6f 2127 }
aaf7a9dc 2128
66035aaf 2129 if (has_capability('mod/forum:splitdiscussions', $modcontext)
2130 && $post->parent && $forumtype != 'single') {
2131
d3583b41 2132 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?prune='.$post->id.
2133 '" title="'.$strpruneheading.'">'.$strprune.'</a>';
cf84431b 2134 }
aaf7a9dc 2135
9fbccd39 2136 if (($ownpost and $age < $CFG->maxeditingtime
2137 and has_capability('mod/forum:deleteownpost', $modcontext))
2138 or has_capability('mod/forum:deleteanypost', $modcontext)) {
d3583b41 2139 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?delete='.$post->id.'">'.$strdelete.'</a>';
64eacd6f 2140 }
359f2758 2141
a4ea3ef3 2142 if ($reply) {
d3583b41 2143 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.$strreply.'</a>';
501cdbd8 2144 }
501cdbd8 2145
d3583b41 2146 echo '<div class="commands">';
2147 echo implode(' | ', $commands);
2148 echo '</div>';
2149
2150
2151/// Ratings
74f5d1e3 2152
2153 $ratingsmenuused = false;
02ebf404 2154 if (!empty($ratings) and !empty($USER->id)) {
d3583b41 2155 echo '<div class="ratings">';
98914efd 2156 $useratings = true;
2157 if ($ratings->assesstimestart and $ratings->assesstimefinish) {
2158 if ($post->created < $ratings->assesstimestart or $post->created > $ratings->assesstimefinish) {
2159 $useratings = false;
2160 }
2161 }
2162 if ($useratings) {
3bd98ad4 2163 $mypost = ($USER->id == $post->userid);
2b63df96 2164
951e1073 2165 $canviewallratings = has_capability('mod/forum:viewanyrating', $modcontext);
2b63df96 2166
2167 if ($canviewallratings and !$mypost) {
951e1073 2168 forum_print_ratings_mean($post->id, $ratings->scale, $canviewallratings);
d395046a 2169 if (!empty($ratings->allow)) {
d3583b41 2170 echo '&nbsp;';
d395046a 2171 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
2172 $ratingsmenuused = true;
2173 }
3bd98ad4 2174
2175 } else if ($mypost) {
2176 forum_print_ratings_mean($post->id, $ratings->scale, true);
2177
98914efd 2178 } else if (!empty($ratings->allow) ) {
2179 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
74f5d1e3 2180 $ratingsmenuused = true;
2a3cda19 2181 }
501cdbd8 2182 }
d3583b41 2183 echo '</div>';
501cdbd8 2184 }
65b0e537 2185
d3583b41 2186/// Link to post if required
2187
501cdbd8 2188 if ($link) {
d3583b41 2189 echo '<div class="link">';
501cdbd8 2190 if ($post->replies == 1) {
d3583b41 2191 $replystring = get_string('repliesone', 'forum', $post->replies);
501cdbd8 2192 } else {
d3583b41 2193 $replystring = get_string('repliesmany', 'forum', $post->replies);
501cdbd8 2194 }
d3583b41 2195 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">'.
2196 get_string('discussthistopic', 'forum').'</a>&nbsp;('.$replystring.')';
2197 echo '</div>';
501cdbd8 2198 }
d3583b41 2199
501cdbd8 2200 if ($footer) {
d3583b41 2201 echo '<div class="footer">'.$footer.'</div>';
501cdbd8 2202 }
d3583b41 2203 echo '</td></tr></table>'."\n\n";
74f5d1e3 2204
eaf50aef 2205 if ($istracked && !$CFG->forum_usermarksread && !empty($post->forum)) {
f37da850 2206 forum_tp_mark_post_read($USER->id, $post, $post->forum);
2207 }
2208
74f5d1e3 2209 return $ratingsmenuused;
501cdbd8 2210}
42fb3c85 2211
2212
eaf50aef 2213/**
2214* This function prints the overview of a discussion in the forum listing.
2215* It needs some discussion information and some post information, these
2216* happen to be combined for efficiency in the $post parameter by the function
2217* that calls this one: forum_print_latest_discussions()
2b63df96 2218*
eaf50aef 2219* @param object $post The post object (passed by reference for speed).
2220* @param object $forum The forum object.
2221* @param int $group Current group.
2222* @param string $datestring Format to use for the dates.
2223* @param boolean $cantrack Is tracking enabled for this forum.
2224* @param boolean $forumtracked Is the user tracking this forum.
2225*/
951e1073 2226function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring="",
2227 $cantrack=true, $forumtracked=true) {
43921b8a 2228
d30867b0 2229 global $USER, $CFG;
3335f6fb 2230
f51e8d7e 2231 static $rowcount;
5733262d 2232 static $strmarkalldread;
f51e8d7e 2233
2b63df96 2234
951e1073 2235 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
2236 error('Course Module ID was incorrect');
2237 }
2238 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2b63df96 2239
951e1073 2240
f51e8d7e 2241 if (!isset($rowcount)) {
2242 $rowcount = 0;
5733262d 2243 $strmarkalldread = get_string('markalldread', 'forum');
f51e8d7e 2244 } else {
2245 $rowcount = ($rowcount + 1) % 2;
2246 }
2247
17dc3f3c 2248 $post->subject = format_string($post->subject,true);
436a7cae 2249
f51e8d7e 2250 echo "\n\n";
2251 echo '<tr class="discussion r'.$rowcount.'">';
3335f6fb 2252
29507631 2253 // Topic
f51e8d7e 2254 echo '<td class="topic starter">';
2255 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">'.$post->subject.'</a>';
29507631 2256 echo "</td>\n";
2257
2258 // Picture
f51e8d7e 2259 echo '<td class="picture">';
a796d0b8 2260 print_user_picture($post->userid, $forum->course, $post->picture);
29507631 2261 echo "</td>\n";
3335f6fb 2262
29507631 2263 // User name
951e1073 2264 $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
f51e8d7e 2265 echo '<td class="author">';
2266 echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->userid.'&amp;course='.$forum->course.'">'.$fullname.'</a>';
29507631 2267 echo "</td>\n";
2268
3a68fbbb 2269 // Group picture
425b4f1a 2270 if ($group !== -1) { // Groups are active - group is a group data object or NULL
f51e8d7e 2271 echo '<td class="picture group">';
c2b552fe 2272 if (!empty($group->picture) and empty($group->hidepicture)) {
3a68fbbb 2273 print_group_picture($group, $forum->course, false, false, true);
2274 } else if (isset($group->id)) {
fa22fd5f 2275 echo '<a href="'.$CFG->wwwroot.'/user/index.php?id='.$forum->course.'&amp;group='.$group->id.'">'.$group->name.'</a>';
3a68fbbb 2276 }
2277 echo "</td>\n";
2278 }
2279
f0da6b85 2280 if (has_capability('mod/forum:viewdiscussion', $modcontext)) { // Show the column with replies
f51e8d7e 2281 echo '<td class="replies">';
2282 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
2283 echo $post->replies.'</a>';
a796d0b8 2284 echo "</td>\n";
e3ff14ca 2285
eaf50aef 2286 if ($cantrack) {
f51e8d7e 2287 echo '<td class="replies">';
eaf50aef 2288 if ($forumtracked) {
2289 if ($post->unread > 0) {
2290 echo '<span class="unread">';
2291 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#unread">';
2292 echo $post->unread;
2293 echo '</a>';
c39748f4 2294 echo '<a title="'.$strmarkalldread.'" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
eaf50aef 2295 $forum->id.'&amp;d='.$post->discussion.'&amp;mark=read&amp;returnpage=view.php">' .
0d905d9f 2296 '<img src="'.$CFG->pixpath.'/t/clear.gif" class="iconsmall" alt="'.$strmarkalldread.'" /></a>';
eaf50aef 2297 echo '</span>';
2298 } else {
2299 echo '<span class="read">';
eaf50aef 2300 echo $post->unread;
eaf50aef 2301 echo '</span>';
2302 }
f51e8d7e 2303 } else {
343af274 2304 echo '<span class="read">';
eaf50aef 2305 echo '-';
343af274 2306 echo '</span>';
3a68fbbb 2307 }
f37da850 2308 echo "</td>\n";
2309 }
a796d0b8 2310 }
3335f6fb 2311
f51e8d7e 2312 echo '<td class="lastpost">';
43921b8a 2313 $usedate = (empty($post->timemodified)) ? $post->modified : $post->timemodified; // Just in case
839f2456 2314 $parenturl = (empty($post->lastpostid)) ? '' : '&amp;parent='.$post->lastpostid;
098d27d4 2315 $usermodified->id = $post->usermodified;
268c6485 2316 $usermodified->firstname = $post->umfirstname;
2317 $usermodified->lastname = $post->umlastname;
f51e8d7e 2318 echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->usermodified.'&amp;course='.$forum->course.'">'.
2319 fullname($usermodified).'</a><br />';
ac00b904 2320 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.$parenturl.'">'.
43921b8a 2321 userdate($usedate, $datestring).'</a>';
29507631 2322 echo "</td>\n";
2323
f51e8d7e 2324 echo "</tr>\n\n";
3335f6fb 2325
3335f6fb 2326}
2327
2328
aa153f29 2329function forum_shorten_post($message) {
c585fa17 2330// Given a post object that we already know has a long message
65b0e537 2331// this function truncates the message nicely to the first
5be7800c 2332// sane place between $CFG->forum_longpost and $CFG->forum_shortpost
2333
2334 global $CFG;
c585fa17 2335
2336 $i = 0;
2337 $tag = false;
2338 $length = strlen($message);
2339 $count = 0;
2340 $stopzone = false;
2341 $truncate = 0;
2342
2343 for ($i=0; $i<$length; $i++) {
a8afb411 2344 $char = $message[$i];
c585fa17 2345
2346 switch ($char) {
65b0e537 2347 case "<":
c585fa17 2348 $tag = true;
2349 break;
65b0e537 2350 case ">":
c585fa17 2351 $tag = false;
2352 break;
2353 default:
2354 if (!$tag) {
2355 if ($stopzone) {
67f0b4cc 2356 if ($char == ".") {
a8afb411 2357 $truncate = $i+1;
c585fa17 2358 break 2;
2359 }
2360 }
2361 $count++;
2362 }
a8afb411 2363 break;
c585fa17 2364 }
2365 if (!$stopzone) {
5be7800c 2366 if ($count > $CFG->forum_shortpost) {
c585fa17 2367 $stopzone = true;
2368 }
2369 }
2370 }
aa153f29 2371
c585fa17 2372 if (!$truncate) {
a8afb411 2373 $truncate = $i;
c585fa17 2374 }
2375
67f0b4cc 2376 return substr($message, 0, $truncate);
aa153f29 2377}
2378
501cdbd8 2379
3bd98ad4 2380function forum_print_ratings_mean($postid, $scale, $link=true) {
02ebf404 2381/// Print the multiple ratings on a post given to the current user by others.
2382/// Scale is an array of ratings
2383
2384 static $strrate;
05c47ef7 2385
2386 $mean = forum_get_ratings_mean($postid, $scale);
65b0e537 2387
05c47ef7 2388 if ($mean !== "") {
02ebf404 2389
2390 if (empty($strratings)) {
2391 $strratings = get_string("ratings", "forum");
501cdbd8 2392 }
501cdbd8 2393
02ebf404 2394 echo "$strratings: ";
3bd98ad4 2395 if ($link) {
2396 link_to_popup_window ("/mod/forum/report.php?id=$postid", "ratings", $mean, 400, 600);
2397 } else {
2398 echo "$mean ";
2399 }
501cdbd8 2400 }
2401}
2402
501cdbd8 2403
0761d83f 2404function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {
2405/// Return the mean rating of a post given to the current user by others.
02ebf404 2406/// Scale is an array of possible ratings in the scale
2407/// Ratings is an optional simple array of actual ratings (just integers)
2408
2409 if (!$ratings) {
2410 $ratings = array();
2411 if ($rates = get_records("forum_ratings", "post", $postid)) {
2412 foreach ($rates as $rate) {
2413 $ratings[] = $rate->rating;
2414 }
501cdbd8 2415 }
501cdbd8 2416 }
02ebf404 2417
0761d83f 2418 $count = count($ratings);
2419
2420 if ($count == 0) {
02ebf404 2421 return "";
02ebf404 2422
0761d83f 2423 } else if ($count == 1) {
2424 return $scale[$ratings[0]];
2425
02ebf404 2426 } else {
0761d83f 2427 $total = 0;
2428 foreach ($ratings as $rating) {
2429 $total += $rating;
2430 }
2431 $mean = round( ((float)$total/(float)$count) + 0.001); // Little fudge factor so that 0.5 goes UP
65b0e537 2432
0761d83f 2433 if (isset($scale[$mean])) {
2434 return $scale[$mean]." ($count)";
2435 } else {
2436 return "$mean ($count)"; // Should never happen, hopefully
2437 }
02ebf404 2438 }
2439}
2440
2441function forum_get_ratings_summary($postid, $scale, $ratings=NULL) {
2442/// Return a summary of post ratings given to the current user by others.
2443/// Scale is an array of possible ratings in the scale
2444/// Ratings is an optional simple array of actual ratings (just integers)
2445
2446 if (!$ratings) {
2447 $ratings = array();
2448 if ($rates = get_records("forum_ratings", "post", $postid)) {
2449 foreach ($rates as $rate) {
2450 $rating[] = $rate->rating;
2451 }
2452 }
2453 }
2454
2455
2456 if (!$count = count($ratings)) {
2457 return "";
2458 }
2459
2460
2461 foreach ($scale as $key => $scaleitem) {
2462 $sumrating[$key] = 0;
2463 }
2464
2465 foreach ($ratings as $rating) {
2466 $sumrating[$rating]++;
2467 }
2468
2469 $summary = "";
2470 foreach ($scale as $key => $scaleitem) {
2471 $summary = $sumrating[$key].$summary;
2472 if ($key > 1) {
2473 $summary = "/$summary";
2474 }
2475 }
2476 return $summary;
2477}
2478
2479function forum_print_rating_menu($postid, $userid, $scale) {
65b0e537 2480/// Print the menu of ratings as part of a larger form.
02ebf404 2481/// If the post has already been - set that value.
2482/// Scale is an array of ratings
2483
2484 static $strrate;
2485
2486 if (!$rating = get_record("forum_ratings", "userid", $userid, "post", $postid)) {
1a7cdb11 2487 $rating->rating = FORUM_UNSET_POST_RATING;
02ebf404 2488 }
2489
2490 if (empty($strrate)) {
2491 $strrate = get_string("rate", "forum");
2492 }
1a7cdb11 2493 $scale = array(FORUM_UNSET_POST_RATING => $strrate.'...') + $scale;
2494 choose_from_menu($scale, $postid, $rating->rating, '');
501cdbd8 2495}
2496
83da3d28 2497/**
2498 * Print the drop down that allows the user to select how they want to have
2499 * the discussion displayed.
2500 * @param $id - forum id if $forumtype is 'single',
2501 * discussion id for any other forum type
2502 * @param $mode - forum layout mode
2503 * @param $forumtype - optional
2504 */
2505function forum_print_mode_form($id, $mode, $forumtype='') {
f0ef40c5 2506 global $FORUM_LAYOUT_MODES;
501cdbd8 2507
83da3d28 2508 if ($forumtype == 'single') {
2509 popup_form("view.php?f=$id&amp;mode=", $FORUM_LAYOUT_MODES, "mode", $mode, "");
2510 } else {
2511 popup_form("discuss.php?d=$id&amp;mode=", $FORUM_LAYOUT_MODES, "mode", $mode, "");
2512 }
501cdbd8 2513}
2514
6f1cc8d6 2515function forum_search_form($course, $search='') {
501cdbd8 2516 global $CFG;
2517
81d22774 2518 $output = '<div class="forumsearch">';
2519 $output .= '<form action="'.$CFG->wwwroot.'/mod/forum/search.php" style="display:inline">';
d69e9c15 2520 $output .= '<fieldset class="invisiblefieldset">';
bbbf2d40 2521 $output .= helpbutton('search', get_string('search'), 'moodle', true, false, '', true);
6f1cc8d6 2522 $output .= '<input name="search" type="text" size="18" value="'.$search.'" alt="search" />';
2523 $output .= '<input value="'.get_string('searchforums', 'forum').'" type="submit" />';
2524 $output .= '<input name="id" type="hidden" value="'.$course->id.'" />';
81d22774 2525 $output .= '</fieldset>';
6f1cc8d6 2526 $output .= '</form>';
81d22774 2527 $output .= '</div>';
5e367a2d 2528
6f1cc8d6 2529 return $output;
501cdbd8 2530}
2531
2532
11b0c469 2533function forum_set_return() {
607809b3 2534 global $CFG, $SESSION;
501cdbd8 2535
28e1e8b9 2536 if (! isset($SESSION->fromdiscussion)) {
48d38fad 2537 if (!empty($_SERVER['HTTP_REFERER'])) {
2538 $referer = $_SERVER['HTTP_REFERER'];
2539 } else {
2540 $referer = "";
2541 }
28e1e8b9 2542 // If the referer is NOT a login screen then save it.
48d38fad 2543 if (! strncasecmp("$CFG->wwwroot/login", $referer, 300)) {
607809b3 2544 $SESSION->fromdiscussion = $_SERVER["HTTP_REFERER"];
28e1e8b9 2545 }
501cdbd8 2546 }
2547}
2548
2549
11b0c469 2550function forum_go_back_to($default) {
501cdbd8 2551 global $SESSION;
2552
9c9f7d77 2553 if (!empty($SESSION->fromdiscussion)) {
501cdbd8 2554 $returnto = $SESSION->fromdiscussion;
2555 unset($SESSION->fromdiscussion);
2556 return $returnto;
2557 } else {
2558 return $default;
2559 }
2560}
2561
7f6689e4 2562function forum_file_area_name($post) {
2563// Creates a directory file name, suitable for make_upload_directory()
2564 global $CFG;
2565
2566 return "$post->course/$CFG->moddata/forum/$post->forum/$post->id";
2567}
2568
2569function forum_file_area($post) {
2570 return make_upload_directory( forum_file_area_name($post) );
2571}
2572
2573function forum_delete_old_attachments($post, $exception="") {
2574// Deletes all the user files in the attachments area for a post
2575// EXCEPT for any file named $exception
2576
2577 if ($basedir = forum_file_area($post)) {
2578 if ($files = get_directory_list($basedir)) {
2579 foreach ($files as $file) {
2580 if ($file != $exception) {
2581 unlink("$basedir/$file");
2582 notify("Existing file '$file' has been deleted!");
2583 }
2584 }
2585 }
2586 if (!$exception) { // Delete directory as well, if empty
2587 rmdir("$basedir");
2588 }
2589 }
2590}
2591
cc2b7ea5 2592function forum_move_attachments($discussion, $forumid) {
65b0e537 2593/// Given a discussion object that is being moved to forumid,
2594/// this function checks all posts in that discussion
2595/// for attachments, and if any are found, these are
cc2b7ea5 2596/// moved to the new forum directory.
2597
2598 global $CFG;
2599
18b8fbfa 2600 require_once($CFG->dirroot.'/lib/uploadlib.php');
2601
cc2b7ea5 2602 $return = true;
2603
2604 if ($posts = get_records_select("forum_posts", "discussion = '$discussion->id' AND attachment <> ''")) {
2605 foreach ($posts as $oldpost) {
2606 $oldpost->course = $discussion->course;
2607 $oldpost->forum = $discussion->forum;
2608 $oldpostdir = "$CFG->dataroot/".forum_file_area_name($oldpost);
2609 if (is_dir($oldpostdir)) {
2610 $newpost = $oldpost;
2611 $newpost->forum = $forumid;
03c9562b 2612 $newpostdir = forum_file_area_name($newpost);
2613 // take off the last directory because otherwise we're renaming to a directory that already exists
2614 // and this is unhappy in certain situations, eg over an nfs mount and potentially on windows too.
2615 make_upload_directory(substr($newpostdir,0,strrpos($newpostdir,'/')));
2616 $newpostdir = $CFG->dataroot.'/'.forum_file_area_name($newpost);
18b8fbfa 2617 $files = get_directory_list($oldpostdir); // get it before we rename it.
cc2b7ea5 2618 if (! @rename($oldpostdir, $newpostdir)) {
2619 $return = false;
2620 }
18b8fbfa 2621 foreach ($files as $file) {
2622 clam_change_log($oldpostdir.'/'.$file,$newpostdir.'/'.$file);
2623 }
cc2b7ea5 2624 }
2625 }
2626 }
2627 return $return;
2628}
2629
7f6689e4 2630function forum_print_attachments($post, $return=NULL) {
2631// if return=html, then return a html string.
2632// if return=text, then return a text-only string.
72d497d4 2633// otherwise, print HTML for non-images, and return image HTML
7f6689e4 2634
2635 global $CFG;
2636
2637 $filearea = forum_file_area_name($post);
2638
72d497d4 2639 $imagereturn = "";
2640 $output = "";
2641
7f6689e4 2642 if ($basedir = forum_file_area($post)) {
2643 if ($files = get_directory_list($basedir)) {
2644 $strattachment = get_string("attachment", "forum");
2645 foreach ($files as $file) {
2646 $icon = mimeinfo("icon", $file);
feaf5d06 2647 $type = mimeinfo("type", $file);
7f6689e4 2648 if ($CFG->slasharguments) {
2a1975cb 2649 $ffurl = "$CFG->wwwroot/file.php/$filearea/$file";
7f6689e4 2650 } else {
2a1975cb 2651 $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
7f6689e4 2652 }
0d905d9f 2653 $image = "<img src=\"$CFG->pixpath/f/$icon\" class=\"icon\" alt=\"\" />";
7f6689e4 2654
2655 if ($return == "html") {
2a1975cb 2656 $output .= "<a href=\"$ffurl\">$image</a> ";
2657 $output .= "<a href=\"$ffurl\">$file</a><br />";
7f6689e4 2658
2659 } else if ($return == "text") {
2a1975cb 2660 $output .= "$strattachment $file:\n$ffurl\n";
7f6689e4 2661
2662 } else {
feaf5d06 2663 if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) { // Image attachments don't get printed as links
2a1975cb 2664 $imagereturn .= "<br /><img src=\"$ffurl\" alt=\"\" />";
72d497d4 2665 } else {
2a1975cb 2666 echo "<a href=\"$ffurl\">$image</a> ";
bce7a133 2667 echo filter_text("<a href=\"$ffurl\">$file</a><br />");
72d497d4 2668 }
7f6689e4 2669 }
2670 }
2671 }
2672 }
72d497d4 2673
7f6689e4 2674 if ($return) {
2675 return $output;
2676 }
72d497d4 2677
2678 return $imagereturn;
7f6689e4 2679}
db290a6e 2680/**
e3ff14ca 2681 * If successful, this function returns the name of the file
db290a6e 2682 * @param $post is a full post record, including course and forum
2683 * @param $newfile is a full upload array from $_FILES
2684 * @param $message is a string to hold the messages.
e3ff14ca 2685 */
7f6689e4 2686
db290a6e 2687function forum_add_attachment($post, $inputname,&$message) {
7f6689e4 2688
9dd0b378 2689 global $CFG;
2690
4909e176 2691 if (!$forum = get_record("forum", "id", $post->forum)) {
2692 return "";
2693 }
2694
2695 if (!$course = get_record("course", "id", $forum->course)) {
2696 return "";
2697 }
2698
5ddaa2e2 2699 require_once($CFG->dirroot.'/lib/uploadlib.php');
db290a6e 2700 $um = new upload_manager($inputname,true,false,$course,false,$forum->maxbytes,true,true);
5ddaa2e2 2701 $dir = forum_file_area_name($post);
2702 if ($um->process_file_uploads($dir)) {
db290a6e 2703 $message .= $um->get_errors();
5ddaa2e2 2704 return $um->get_new_filename();
7f6689e4 2705 }
db290a6e 2706 $message .= $um->get_errors();
feaf5d06 2707 return null;
7f6689e4 2708}
501cdbd8 2709
db290a6e 2710function forum_add_new_post($post,&$message) {
501cdbd8 2711
f37da850 2712 global $USER, $CFG;
e3ff14ca 2713
ffe11640 2714 $post->created = $post->modified = time();
501cdbd8 2715 $post->mailed = "0";
a56f0d60 2716 $post->userid = $USER->id;
7f6689e4 2717 $post->attachment = "";
2718
65b0e537 2719 if (! $post->id = insert_record("forum_posts", $post)) {
7f6689e4 2720 return false;
2721 }
2722
db290a6e 2723 if ($post->attachment = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 2724 set_field("forum_posts", "attachment", $post->attachment, "id", $post->id);
2725 }
29507631 2726
2727 // Update discussion modified date
2728 set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
016cd6af 2729 set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
65b0e537 2730
eaf50aef 2731 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 2732 forum_tp_mark_post_read($post->userid, $post, $post->forum);
2733 }
2734
7f6689e4 2735 return $post->id;
501cdbd8 2736}
2737
db290a6e 2738function forum_update_post($post,&$message) {
501cdbd8 2739
f37da850 2740 global $USER, $CFG;
a56f0d60 2741
ffe11640 2742 $post->modified = time();
0936de64 2743
0ab85112 2744 if (!$post->parent) { // Post is a discussion starter - update discussion title too
2745 set_field("forum_discussions", "name", $post->subject, "id", $post->discussion);
2746 }
29507631 2747
db290a6e 2748 if ($newfilename = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 2749 $post->attachment = $newfilename;
2750 } else {
2751 unset($post->attachment);
2752 }
29507631 2753
2754 // Update discussion modified date
2755 set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
016cd6af 2756 set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
29507631 2757
eaf50aef 2758 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 2759 forum_tp_mark_post_read($post->userid, $post, $post->forum);
2760 }
2761
ffe11640 2762 return update_record("forum_posts", $post);
501cdbd8 2763}
2764
db290a6e 2765function forum_add_discussion($discussion,&$message) {
65b0e537 2766// Given an object containing all the necessary data,
501cdbd8 2767// create a new discussion and return the id
2768
f37da850 2769 GLOBAL $USER, $CFG;
501cdbd8 2770
2771 $timenow = time();
2772
65b0e537 2773 // The first post is stored as a real post, and linked
501cdbd8 2774 // to from the discuss entry.
2775
2776 $post->discussion = 0;
2777 $post->parent = 0;
ebc3bd2b 2778 $post->userid = $USER->id;
501cdbd8 2779 $post->created = $timenow;
2780 $post->modified = $timenow;
2781 $post->mailed = 0;
2782 $post->subject = $discussion->name;
2783 $post->message = $discussion->intro;
7f6689e4 2784 $post->attachment = "";
2785 $post->forum = $discussion->forum;
2786 $post->course = $discussion->course;
9f0b8269 2787 $post->format = $discussion->format;
41547057 2788 $post->mailnow = $discussion->mailnow;
501cdbd8 2789
2790 if (! $post->id = insert_record("forum_posts", $post) ) {
2791 return 0;
2792 }
2793
db290a6e 2794 if ($post->attachment = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 2795 set_field("forum_posts", "attachment", $post->attachment, "id", $post->id); //ignore errors
2796 }
2797
65b0e537 2798 // Now do the main entry for the discussion,
02509fe6 2799 // linking to this first post
04eba58f 2800
caadf009 2801 $discussion->firstpost = $post->id;
2802 $discussion->timemodified = $timenow;
016cd6af 2803 $discussion->usermodified = $post->userid;
a56f0d60 2804 $discussion->userid = $USER->id;
04eba58f 2805
4e00a4d9 2806 if (! $post->discussion = insert_record("forum_discussions", $discussion) ) {
caadf009 2807 delete_records("forum_posts", "id", $post->id);
2808 return 0;
04eba58f 2809 }
2810
caadf009 2811 // Finally, set the pointer on the post.
4e00a4d9 2812 if (! set_field("forum_posts", "discussion", $post->discussion, "id", $post->id)) {
caadf009 2813 delete_records("forum_posts", "id", $post->id);
4e00a4d9 2814 delete_records("forum_discussions", "id", $post->discussion);
caadf009 2815 return 0;
04eba58f 2816 }
04eba58f 2817
eaf50aef 2818 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 2819 forum_tp_mark_post_read($post->userid, $post, $post->forum);
2820 }
2821
4e00a4d9 2822 return $post->discussion;
caadf009 2823}
04eba58f 2824
04eba58f 2825
e2c1dbe9 2826function forum_delete_discussion($discussion, $fulldelete=false) {
caadf009 2827// $discussion is a discussion record object
04eba58f 2828
2829 $result = true;
2830
caadf009 2831 if ($posts = get_records("forum_posts", "discussion", $discussion->id)) {
2832 foreach ($posts as $post) {
2833 $post->course = $discussion->course;
2834 $post->forum = $discussion->forum;
2835 if (! delete_records("forum_ratings", "post", "$post->id")) {
2836 $result = false;
2837 }
e2c1dbe9 2838 if (! forum_delete_post($post, $fulldelete)) {
04eba58f 2839 $result = false;
2840 }
2841 }
2842 }
2843
f37da850 2844 forum_tp_delete_read_records(-1, -1, $discussion->id);
2845
caadf009 2846 if (! delete_records("forum_discussions", "id", "$discussion->id")) {
04eba58f 2847 $result = false;
2848 }
2849
2850 return $result;
2851}
2852
2853
b82faacd 2854function forum_delete_post($post, $children=false) {
1da8c568 2855 if ($childposts = get_records('forum_posts', 'parent', $post->id)) {
2856 if ($children) {
b82faacd 2857 foreach ($childposts as $childpost) {
2858 forum_delete_post($childpost, true);
2859 }
1da8c568 2860 } else {
2861 return false;
b82faacd 2862 }
2863 }
caadf009 2864 if (delete_records("forum_posts", "id", $post->id)) {
2865 delete_records("forum_ratings", "post", $post->id); // Just in case
f37da850 2866
b82faacd 2867 forum_tp_delete_read_records(-1, $post->id);
f37da850 2868
caadf009 2869 if ($post->attachment) {
2870 $discussion = get_record("forum_discussions", "id", $post->discussion);
2871 $post->course = $discussion->course;
2872 $post->forum = $discussion->forum;
2873 forum_delete_old_attachments($post);
2874 }
1da8c568 2875
2876 /// Just in case we are deleting the last post
2877 forum_discussion_update_last_post($post->discussion);
2878
caadf009 2879 return true;
2880 }
2881 return false;
2882}
501cdbd8 2883
b82faacd 2884function forum_count_replies($post, $children=true) {
2885 $count = 0;
2886
2887 if ($children) {
2888 if ($childposts = get_records('forum_posts', 'parent', $post->id)) {
2889 foreach ($childposts as $childpost) {
2890 $count ++; // For this child
2891 $count += forum_count_replies($childpost, true);
2892 }
2893 }
2894 } else {
2895 $count += count_records('forum_posts', 'parent', $post->id);
2896 }
2897
2898 return $count;
2899}
2900
2901
501cdbd8 2902function forum_forcesubscribe($forumid, $value=1) {
2903 return set_field("forum", "forcesubscribe", $value, "id", $forumid);
2904}
2905
2906function forum_is_forcesubscribed($forumid) {
709f0ec8 2907 return (get_field("forum", "forcesubscribe", "id", $forumid) == 1);
501cdbd8 2908}
2909
2910function forum_is_subscribed($userid, $forumid) {
2911 if (forum_is_forcesubscribed($forumid)) {
2912 return true;
2913 }
ebc3bd2b 2914 return record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid);
86970225 2915}
2916
501cdbd8 2917function forum_subscribe($userid, $forumid) {
9fa49e22 2918/// Adds user to the subscriber list
2919
6673d7bd 2920 if (record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid)) {
2921 return true;
2922 }
2923
ebc3bd2b 2924 $sub->userid = $userid;
9fa49e22 2925 $sub->forum = $forumid;
501cdbd8 2926
9fa49e22 2927 return insert_record("forum_subscriptions", $sub);
501cdbd8 2928}
2929
2930function forum_unsubscribe($userid, $forumid) {
9fa49e22 2931/// Removes user from the subscriber list
ebc3bd2b 2932 return delete_records("forum_subscriptions", "userid", $userid, "forum", $forumid);
501cdbd8 2933}
2934
0a9f61b5 2935function forum_post_subscription($post) {
2936/// Given a new post, subscribes or unsubscribes as appropriate.
2937/// Returns some text which describes what happened.
2938
2939 global $USER;
2940
2b63df96 2941 $subscribed=forum_is_subscribed($USER->id, $post->forum);
2942 if ((isset($post->subscribe) && $post->subscribe && $subscribed)
2943 || (!$post->subscribe && !$subscribed)) {
0a9f61b5 2944 return "";
2945 }
2946
2947 if (!$forum = get_record("forum", "id", $post->forum)) {
2948 return "";
2949 }
2950
067675c0 2951 $info->name = fullname($USER);
0a9f61b5 2952 $info->forum = $forum->name;
2953
2954 if (!empty($post->subscribe)) {
2955 forum_subscribe($USER->id, $post->forum);
2956 return "<p>".get_string("nowsubscribed", "forum", $info)."</p>";
2957 }
2958
2959 forum_unsubscribe($USER->id, $post->forum);
2960 return "<p>".get_string("nownotsubscribed", "forum", $info)."</p>";
2961}
2962
501cdbd8 2963
11b0c469 2964function forum_user_has_posted_discussion($forumid, $userid) {
d50704bf 2965 if ($discussions = forum_get_discussions($forumid, '', $userid)) {
501cdbd8 2966 return true;
2967 } else {
2968 return false;
2969 }
2970}
2971
dcd8e589 2972function forum_discussions_user_has_posted_in($forumid, $userid) {
2973 global $CFG;
2974
0b9873f2 2975 $haspostedsql = "SELECT d.id AS id,
dcd8e589 2976 d.*
f274fe07 2977 FROM {$CFG->prefix}forum_posts p,
2978 {$CFG->prefix}forum_discussions d
dcd8e589 2979 WHERE p.discussion = d.id
2980 AND d.forum = $forumid
2981 AND p.userid = $userid";
2982
2983 return get_records_sql($haspostedsql);
2984}
2985
bbbf2d40 2986function forum_user_has_posted($forumid, $did, $userid) {
098d27d4 2987 return record_exists('forum_posts','discussion',$did,'userid',$userid);
2988}
2989
918e9805 2990function forum_user_can_post_discussion($forum, $currentgroup=false, $groupmode=false, $cm=NULL, $context=NULL) {
501cdbd8 2991// $forum is an object
fa22fd5f 2992 global $USER, $SESSION;
bbbf2d40 2993
918e9805 2994 if (!$cm) {
2995 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
2996 error('Course Module ID was incorrect');
2997 }
2998 }
2999 if (!$context) {
3000 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
bbbf2d40 3001 }
bbbf2d40 3002
33e21153 3003 if (!has_capability('mod/forum:startdiscussion', $context)) {
bbbf2d40 3004 return false;
3005 }
3006
33e21153 3007 if ($forum->type == "eachuser") {
bbbf2d40 3008 return (!forum_user_has_posted_discussion($forum->id, $USER->id));
9197e147 3009 } else if ($currentgroup) {
0468976c 3010 return (has_capability('moodle/site:accessallgroups', $context)
f0da6b85 3011 or ismember($currentgroup));
501cdbd8 3012 } else {
fa22fd5f 3013 //else it might be group 0 in visible mode
3014 if ($groupmode == VISIBLEGROUPS){
f0da6b85 3015 return (ismember($currentgroup));
fa22fd5f 3016 }
3017 else {
f0da6b85 3018 return true;
fa22fd5f 3019 }
501cdbd8 3020 }
3021}
3022
bbbf2d40 3023/**
3024 * This function checks whether the user can reply to posts in a forum
3025 * discussion. Use forum_user_can_post_discussion() to check whether the user
3026 * can start dicussions.
3027 * @param $forum - forum object
3028 * @param $user - user object
3029 */
918e9805 3030function forum_user_can_post($forum, $user=NULL, $cm=NULL, $context=NULL) {
f690562f 3031
918e9805 3032 if (!$cm) {
3033 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
3034 error('Course Module ID was incorrect');
3035 }
3036 }
3037 if (!$context) {
3038 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
f690562f 3039 }
70c476a7 3040
33e21153 3041 if (isset($user)) {
3042 $canreply = has_capability('mod/forum:replypost', $context, $user->id, false)
a4ea3ef3 3043 && !has_capability('moodle/legacy:guest', $context, $user->id, false);
70c476a7 3044 } else {
33e21153 3045 $canreply = has_capability('mod/forum:replypost', $context, NULL, false)
a4ea3ef3 3046 && !has_capability('moodle/legacy:guest', $context, NULL, false);
70c476a7 3047 }
bbbf2d40 3048
3049 return $canreply;
70c476a7 3050}
501cdbd8 3051
bbbf2d40 3052
073286f0 3053//checks to see if a user can view a particular post
ff1dc046 3054function forum_user_can_view_post($post, $course, $cm, $forum, $discussion, $user=NULL){
073286f0 3055
3056 global $CFG, $USER;
2b63df96 3057
073286f0 3058 if (!$user){
3059 $user = $USER;
3060 }
2b63df96 3061
bbbf2d40 3062 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
0468976c 3063 if (!has_capability('mod/forum:viewdiscussion', $modcontext)) {
bbbf2d40 3064 return false;
073286f0 3065 }
073286f0 3066
ff1dc046 3067/// If it's a grouped discussion, make sure the user is a member
3068 if ($discussion->groupid > 0) {
33e21153 3069 if ($cm->groupmode == SEPARATEGROUPS) {
3070 return ismember($discussion->groupid) ||
3071 has_capability('moodle/site:accessallgroups', $modcontext);
ff1dc046 3072 }
073286f0 3073 }
ff1dc046 3074 return true;
073286f0 3075}
501cdbd8 3076
bbbf2d40 3077
951e1073 3078function forum_user_can_see_discussion($forum, $discussion, $context, $user=NULL) {
098d27d4 3079 global $USER;
3080
3081 if (empty($user) || empty($user->id)) {
3082 $user = $USER;
3083 }
3084
669f2499 3085 // retrieve objects (yuk)
098d27d4 3086 if (is_numeric($forum)) {
3087 if (!$forum = get_record('forum','id',$forum)) {
3088 return false;
3089 }
3090 }
3091 if (is_numeric($discussion)) {
3092 if (!$discussion = get_record('forum_discussions','id',$discussion)) {
3093 return false;
3094 }
3095 }
2b63df96 3096
951e1073 3097 if (!has_capability('mod/forum:viewdiscussion', $context)) {
bbbf2d40 3098 return false;
3099 }
2b63df96 3100
bbbf2d40 3101 if ($forum->type == 'qanda' &&
3102 !forum_user_has_posted($forum->id, $discussion->id, $user->id) &&
951e1073 3103 !has_capability('mod/forum:viewqandawithoutposting', $context)) {
bbbf2d40 3104 return false;
098d27d4 3105 }
3106 return true;
3107}
2b63df96 3108
098d27d4 3109
bbbf2d40 3110function forum_user_can_see_post($forum, $discussion, $post, $user=NULL) {
098d27d4 3111 global $USER;
3112
669f2499 3113 // retrieve objects (yuk)
098d27d4 3114 if (is_numeric($forum)) {
3115 if (!$forum = get_record('forum','id',$forum)) {
3116 return false;
3117 }
3118 }
2b63df96 3119
098d27d4 3120 if (is_numeric($discussion)) {
2b63df96 3121 if (!$discussion = get_record('forum_discussions','id',$discussion)) {
098d27d4 3122 return false;
3123 }
3124 }
3125 if (is_numeric($post)) {