merged fix for MDL-8821, do not display grade table when no grade
[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);
096c91af 1203 $courses2 = get_my_courses($userid, 'visible DESC,sortorder ASC', '*', true);
6155150c 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();
532daab4 1380 /// Experimental feature under 1.8! MDL-8830
1381 /// Use alternative text searches if defined
1382 /// This feature only works under mysql until properly implemented for other DBs
1383 /// Requires manual creation of text index for forum_posts before enabling it:
1384 /// CREATE FULLTEXT INDEX foru_post_tix ON [prefix]forum_posts (subject, message)
1385 /// Experimental feature under 1.8! MDL-8830
1386 if (!empty($CFG->forum_usetextsearches)) {
1387 $messagesearch = search_generate_text_SQL($parsearray, 'p.message', 'p.subject',
1388 'p.userid', 'u.id', 'u.firstname',
1389 'u.lastname', 'p.modified', 'd.forum');
1390 } else {
1391 $messagesearch = search_generate_SQL($parsearray, 'p.message', 'p.subject',
1392 'p.userid', 'u.id', 'u.firstname',
1393 'u.lastname', 'p.modified', 'd.forum');
1394 }
42fb3c85 1395 }
1396
1397 $fromsql = "{$CFG->prefix}forum_posts p,
1398 {$CFG->prefix}forum_discussions d,
1399 {$CFG->prefix}user u";
1400
1401 $selectsql = " $messagesearch
1402 AND p.discussion = d.id
1403 AND p.userid = u.id
1404 AND $selectdiscussion
1405 $extrasql";
1406
1407 $countsql = "SELECT COUNT(*)
1408 FROM $fromsql
1409 WHERE $selectsql";
1410
7f094149 1411 $searchsql = "SELECT p.*,
42fb3c85 1412 d.forum,
1413 u.firstname,
1414 u.lastname,
1415 u.email,
1416 u.picture
1417 FROM $fromsql
1418 WHERE $selectsql
1419 ORDER BY p.modified DESC";
1420
b1342e18 1421 $totalcount = count_records_sql($countsql);
d50704bf 1422
67875aa1 1423 return get_records_sql($searchsql, $limitfrom, $limitnum);
42fb3c85 1424}
1425
9fa49e22 1426function forum_get_ratings($postid, $sort="u.firstname ASC") {
1427/// Returns a list of ratings for a particular post - sorted.
1428 global $CFG;
65b0e537 1429 return get_records_sql("SELECT u.*, r.rating, r.time
1430 FROM {$CFG->prefix}forum_ratings r,
9fa49e22 1431 {$CFG->prefix}user u
65b0e537 1432 WHERE r.post = '$postid'
1433 AND r.userid = u.id
9fa49e22 1434 ORDER BY $sort");
1435}
1436
3ecca1ee 1437function forum_get_unmailed_posts($starttime, $endtime) {
1f48942e 1438/// Returns a list of all new posts that have not been mailed yet
1439 global $CFG;
fbc21e82 1440 $now = time();
65b0e537 1441 return get_records_sql("SELECT p.*, d.course
1442 FROM {$CFG->prefix}forum_posts p,
1f48942e 1443 {$CFG->prefix}forum_discussions d
65b0e537 1444 WHERE p.mailed = 0
b12d055a 1445 AND (p.created >= '$starttime' OR d.timestart > 0)
41547057 1446 AND (p.created < '$endtime' OR p.mailnow = 1)
c274b0e0 1447 AND p.discussion = d.id
fbc21e82 1448 AND ((d.timestart = 0 OR d.timestart <= '$now')
1449 AND (d.timeend = 0 OR d.timeend > '$now'))
0fcac008 1450 ORDER BY p.modified ASC");
1f48942e 1451}
1452
3ecca1ee 1453function forum_mark_old_posts_as_mailed($endtime) {
1454/// Marks posts before a certain time as being mailed already
1455 global $CFG;
0f620d4b 1456/// Find out posts those are not showing immediately so we can exclude them
1457 $now = time();
1458 $delayed_posts = get_records_sql("SELECT p.id, p.discussion
1459 FROM {$CFG->prefix}forum_posts p,
1460 {$CFG->prefix}forum_discussions d
1461 WHERE p.mailed = 0
1462 AND p.discussion = d.id
1463 AND d.timestart > '$now'");
1464 $delayed_ids = array();
1465 if ($delayed_posts) {
1466 foreach ($delayed_posts as $post) {
1467 $delayed_ids[] = $post->id;
1468 }
1469 } else {
1470 $delayed_ids[] = 0;
1471 }
c274b0e0 1472 return execute_sql("UPDATE {$CFG->prefix}forum_posts
1473 SET mailed = '1'
9ed7d7e1 1474 WHERE id NOT IN (".implode(',',$delayed_ids).")
1475 AND (created < '$endtime' OR mailnow = 1)
1476 AND mailed ='0'", false);
3ecca1ee 1477}
1478
1f48942e 1479function forum_get_user_posts($forumid, $userid) {
1480/// Get all the posts for a user in a forum suitable for forum_print_post
1481 global $CFG;
1482
77efef3e 1483 return get_records_sql("SELECT p.*, d.forum, u.firstname, u.lastname, u.email, u.picture
65b0e537 1484 FROM {$CFG->prefix}forum f,
1485 {$CFG->prefix}forum_discussions d,
1486 {$CFG->prefix}forum_posts p,
1487 {$CFG->prefix}user u
1488 WHERE f.id = '$forumid'
1489 AND d.forum = f.id
1f48942e 1490 AND p.discussion = d.id
65b0e537 1491 AND p.userid = '$userid'
ebc3bd2b 1492 AND p.userid = u.id
1f48942e 1493 ORDER BY p.modified ASC");
1494}
1495
1496function forum_get_post_from_log($log) {
1497/// Given a log entry, return the forum post details for it.
1498 global $CFG;
1499
1500 if ($log->action == "add post") {
1501
2b63df96 1502 return get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
8f7dc7f1 1503 u.firstname, u.lastname, u.email, u.picture
65b0e537 1504 FROM {$CFG->prefix}forum_discussions d,
1505 {$CFG->prefix}forum_posts p,
8f7dc7f1 1506 {$CFG->prefix}forum f,
65b0e537 1507 {$CFG->prefix}user u
1508 WHERE p.id = '$log->info'
1509 AND d.id = p.discussion
1510 AND p.userid = u.id
8f7dc7f1 1511 AND u.deleted <> '1'
1512 AND f.id = d.forum");
1f48942e 1513
1514
1515 } else if ($log->action == "add discussion") {
1516
2b63df96 1517 return get_record_sql("SELECT p.*, f.type AS forumtype, d.forum, d.groupid,
8f7dc7f1 1518 u.firstname, u.lastname, u.email, u.picture
65b0e537 1519 FROM {$CFG->prefix}forum_discussions d,
1520 {$CFG->prefix}forum_posts p,
8f7dc7f1 1521 {$CFG->prefix}forum f,
65b0e537 1522 {$CFG->prefix}user u
1523 WHERE d.id = '$log->info'
1524 AND d.firstpost = p.id
1525 AND p.userid = u.id
8f7dc7f1 1526 AND u.deleted <> '1'
1527 AND f.id = d.forum");
1f48942e 1528 }
1529 return NULL;
1530}
1531
d05956ac 1532function forum_get_firstpost_from_discussion($discussionid) {
1533/// Given a discussion id, return the first post from the discussion
1534 global $CFG;
1535
1536 return get_record_sql("SELECT p.*
65b0e537 1537 FROM {$CFG->prefix}forum_discussions d,
d05956ac 1538 {$CFG->prefix}forum_posts p
65b0e537 1539 WHERE d.id = '$discussionid'
d05956ac 1540 AND d.firstpost = p.id ");
1541}
1542
1f48942e 1543
1544function forum_get_user_grades($forumid) {
1545/// Get all user grades for a forum
1546 global $CFG;
1547
ebc3bd2b 1548 return get_records_sql("SELECT r.id, p.userid, r.rating
65b0e537 1549 FROM {$CFG->prefix}forum_discussions d,
1550 {$CFG->prefix}forum_posts p,
1f48942e 1551 {$CFG->prefix}forum_ratings r
65b0e537 1552 WHERE d.forum = '$forumid'
1f48942e 1553 AND p.discussion = d.id
02ebf404 1554 AND r.post = p.id
1555 ORDER by p.userid ");
1f48942e 1556}
1557
1558
a48e8c4b 1559function forum_count_discussion_replies($forum='0', $course='0', $user='0') {
1560// Returns an array of counts of replies to each discussion (optionally in one forum or course and/or user)
1f48942e 1561 global $CFG;
1562
a48e8c4b 1563 $forumselect = $courseselect = $userselect = '';
1564
1f48942e 1565 if ($forum) {
1566 $forumselect = " AND d.forum = '$forum'";
a48e8c4b 1567 }
1568 if ($course) {
1569 $courseselect = " AND d.course = '$course'";
1570 }
1571 if ($user) {
1572 $userselect = " AND d.userid = '$user'";
1f48942e 1573 }
3599e487 1574 return get_records_sql("SELECT p.discussion, (count(*)) as replies, max(p.id) as lastpostid
65b0e537 1575 FROM {$CFG->prefix}forum_posts p,
1f48942e 1576 {$CFG->prefix}forum_discussions d
a48e8c4b 1577 WHERE p.parent > 0 $forumselect $courseselect $userselect
1c887009 1578 AND p.discussion = d.id
1f48942e 1579 GROUP BY p.discussion");
1580}
1581
1582function forum_count_unrated_posts($discussionid, $userid) {
1583// How many unrated posts are in the given discussion for a given user?
1584 global $CFG;
1585 if ($posts = get_record_sql("SELECT count(*) as num
1586 FROM {$CFG->prefix}forum_posts
65b0e537 1587 WHERE parent > 0
1588 AND discussion = '$discussionid'
ebc3bd2b 1589 AND userid <> '$userid' ")) {
1f48942e 1590
65b0e537 1591 if ($rated = get_record_sql("SELECT count(*) as num
1592 FROM {$CFG->prefix}forum_posts p,
1f48942e 1593 {$CFG->prefix}forum_ratings r
1594 WHERE p.discussion = '$discussionid'
65b0e537 1595 AND p.id = r.post
ebc3bd2b 1596 AND r.userid = '$userid'")) {
1f48942e 1597 $difference = $posts->num - $rated->num;
1598 if ($difference > 0) {
1599 return $difference;
1600 } else {
1601 return 0; // Just in case there was a counting error
1602 }
1603 } else {
1604 return $posts->num;
1605 }
1606 } else {
1607 return 0;
1608 }
1609}
1610
65b0e537 1611function forum_get_discussions($forum="0", $forumsort="d.timemodified DESC",
13597d01 1612 $user=0, $fullpost=true, $visiblegroups=-1, $limit=0, $userlastmodified=false) {
1f48942e 1613/// Get all discussions in a forum
fbc21e82 1614 global $CFG, $USER;
0fcac008 1615
3d284127 1616 $timelimit = '';
1617
1618 if (!empty($CFG->forum_enabletimedposts)) {
2b63df96 1619
7613e6d7 1620 if (!$cm = get_coursemodule_from_instance('forum', $forum)) {
1621 error('Course Module ID was incorrect');
1622 }
1623 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2b63df96 1624
0468976c 1625 if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
3d284127 1626 $now = time();
1627 $timelimit = " AND ((d.timestart = 0 OR d.timestart <= '$now') AND (d.timeend = 0 OR d.timeend > '$now')";
1628 if (!empty($USER->id)) {
1629 $timelimit .= " OR d.userid = '$USER->id'";
1630 }
1631 $timelimit .= ')';
fbc21e82 1632 }
fbc21e82 1633 }
1f48942e 1634
1635 if ($user) {
1636 $userselect = " AND u.id = '$user' ";
1637 } else {
1638 $userselect = "";
1639 }
2862b309 1640
9eabd190 1641 $limitfrom = 0;
1642 $limitnum = 0;
90ec387a 1643 if ($limit) {
9eabd190 1644 $limitnum = $limit;
90ec387a 1645 }
8f0cd6ef 1646
2862b309 1647 if ($visiblegroups == -1) {
02509fe6 1648 $groupselect = "";
2862b309 1649 } else {
1650 $groupselect = " AND (d.groupid = '$visiblegroups' OR d.groupid = '-1') ";
02509fe6 1651 }
2862b309 1652
29507631 1653 if (empty($forumsort)) {
1654 $forumsort = "d.timemodified DESC";
1655 }
2ab968e9 1656 if (empty($fullpost)) {
b879effb 1657 $postdata = "p.id,p.subject,p.modified,p.discussion,p.userid";
2ab968e9 1658 } else {
1659 $postdata = "p.*";
1660 }
9197e147 1661
13597d01 1662 if (empty($userlastmodified)) { // We don't need to know this
1663 $umfields = '';
1664 $umtable = '';
13597d01 1665 } else {
096de9ad 1666 $umfields = ', um.firstname AS umfirstname, um.lastname AS umlastname';
cfdc10e6 1667 $umtable = ' LEFT JOIN '.$CFG->prefix.'user um on (d.usermodified = um.id)';
13597d01 1668 }
1669
80d3523e 1670 //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 1671 if ($CFG->dbfamily == 'postgres' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'oracle') {
80d3523e 1672 return get_records_sql("SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid,
13597d01 1673 u.firstname, u.lastname, u.email, u.picture $umfields
93d58b30 1674 FROM {$CFG->prefix}forum_discussions d
1675 JOIN {$CFG->prefix}forum_posts p ON p.discussion = d.id
1676 JOIN {$CFG->prefix}user u ON p.userid = u.id
13597d01 1677 $umtable
65b0e537 1678 WHERE d.forum = '$forum'
65b0e537 1679 AND p.parent = 0
2b63df96 1680 $timelimit $groupselect $userselect
9eabd190 1681 ORDER BY $forumsort", $limitfrom, $limitnum);
a4bad45c 1682 } else { // MySQL query. TODO: Check if this is needed (MySQL 4.1 should work with the above query)
80d3523e 1683 return get_records_sql("SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid,
1684 u.firstname, u.lastname, u.email, u.picture $umfields
fd6590a9 1685 FROM ({$CFG->prefix}forum_posts p,
b73b9d81 1686 {$CFG->prefix}user u,
fd6590a9 1687 {$CFG->prefix}forum_discussions d)
80d3523e 1688 $umtable
1689 WHERE d.forum = '$forum'
1690 AND p.discussion = d.id
1691 AND p.parent = 0
80329e02 1692 AND p.userid = u.id $timelimit $groupselect $userselect
9eabd190 1693 ORDER BY $forumsort", $limitfrom, $limitnum);
80d3523e 1694 }
1f48942e 1695}
1696
1697
1698
b656e2a9 1699function forum_get_user_discussions($courseid, $userid, $groupid=0) {
1700/// Get all discussions started by a particular user in a course (or group)
4f321bdb 1701/// This function no longer used ...
1f48942e 1702 global $CFG;
1703
b656e2a9 1704 if ($groupid) {
1705 $groupselect = " AND d.groupid = '$groupid' ";
1706 } else {
1707 $groupselect = "";
1708 }
1709
2862b309 1710 return get_records_sql("SELECT p.*, d.groupid, u.firstname, u.lastname, u.email, u.picture,
ebc3bd2b 1711 f.type as forumtype, f.name as forumname, f.id as forumid
65b0e537 1712 FROM {$CFG->prefix}forum_discussions d,
1713 {$CFG->prefix}forum_posts p,
1714 {$CFG->prefix}user u,
1f48942e 1715 {$CFG->prefix}forum f
65b0e537 1716 WHERE d.course = '$courseid'
1717 AND p.discussion = d.id
1718 AND p.parent = 0
1719 AND p.userid = u.id
1720 AND u.id = '$userid'
b656e2a9 1721 AND d.forum = f.id $groupselect
b8bf90c5 1722 ORDER BY p.created DESC");
1f48942e 1723}
1724
669f2499 1725function forum_subscribed_users($course, $forum, $groupid=0, $cache=false) {
1f48942e 1726/// Returns list of user objects that are subscribed to this forum
1727 global $CFG;
1728
669f2499 1729 static $resultscache = array();
1730
1731 if ($cache && isset($resultscache[$forum->id][$groupid])) {
1732 return $resultscache[$forum->id][$groupid];
1733 }
1734
6673d7bd 1735 if ($groupid) {
e25cb710 1736 $grouptables = ', '. groups_members_from_sql();
1737 $groupselect = 'AND'.groups_members_where_sql($groupid, 'u.id');
6673d7bd 1738 } else {
669f2499 1739 $grouptables = '';
1740 $groupselect = '';
6673d7bd 1741 }
1742
709f0ec8 1743 if (forum_is_forcesubscribed($forum->id)) {
669f2499 1744 $results = get_course_users($course->id); // Otherwise get everyone in the course
1745 } else {
1746 $results = get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat, u.maildigest, u.emailstop,
9152fc99 1747 u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.timezone, u.theme, u.lang, u.trackforums
65b0e537 1748 FROM {$CFG->prefix}user u,
6673d7bd 1749 {$CFG->prefix}forum_subscriptions s $grouptables
1f48942e 1750 WHERE s.forum = '$forum->id'
65b0e537 1751 AND s.userid = u.id
6673d7bd 1752 AND u.deleted <> 1 $groupselect
7c81b6e2 1753 ORDER BY u.email ASC");
669f2499 1754 }
b725b819 1755 // Guest user should never be subscribed to a forum.
1756 if ($guest = guest_user()) {
1757 unset($results[$guest->id]);
1758 }
669f2499 1759
1760 if ($cache) {
1761 $resultscache[$forum->id][$groupid] = $results;
1762 }
1763
1764 return $results;
1f48942e 1765}
9fa49e22 1766
067675c0 1767
1768
caadf009 1769/// OTHER FUNCTIONS ///////////////////////////////////////////////////////////
f93f848a 1770
1771
11b0c469 1772function forum_get_course_forum($courseid, $type) {
1773// How to set up special 1-per-course forums
a6fcdf98 1774 global $CFG;
1775
29cbd93a 1776 if ($forums = get_records_select("forum", "course = '$courseid' AND type = '$type'", "id ASC")) {
65b0e537 1777 // There should always only be ONE, but with the right combination of
29cbd93a 1778 // errors there might be more. In this case, just return the oldest one (lowest ID).
1779 foreach ($forums as $forum) {
1780 return $forum; // ie the first one
11b0c469 1781 }
8daaf761 1782 }
e6874d9f 1783
8daaf761 1784 // Doesn't exist, so create one now.
1785 $forum->course = $courseid;
1786 $forum->type = "$type";
1787 switch ($forum->type) {
1788 case "news":
65a3ef30 1789 $forum->name = addslashes(get_string("namenews", "forum"));
1790 $forum->intro = addslashes(get_string("intronews", "forum"));
906fef94 1791 $forum->forcesubscribe = FORUM_FORCESUBSCRIBE;
8daaf761 1792 $forum->assessed = 0;
709f0ec8 1793 if ($courseid == SITEID) {
1794 $forum->name = get_string("sitenews");
1795 $forum->forcesubscribe = 0;
8f0cd6ef 1796 }
8daaf761 1797 break;
1798 case "social":
65a3ef30 1799 $forum->name = addslashes(get_string("namesocial", "forum"));
1800 $forum->intro = addslashes(get_string("introsocial", "forum"));
8daaf761 1801 $forum->assessed = 0;
1802 $forum->forcesubscribe = 0;
1803 break;
8daaf761 1804 default:
1805 notify("That forum type doesn't exist!");
1806 return false;
1807 break;
1808 }
1809
1810 $forum->timemodified = time();
1811 $forum->id = insert_record("forum", $forum);
1812
e1b5643f 1813 if (! $module = get_record("modules", "name", "forum")) {
1814 notify("Could not find forum module!!");
1815 return false;
82aa0e8d 1816 }
e1b5643f 1817 $mod->course = $courseid;
1818 $mod->module = $module->id;
1819 $mod->instance = $forum->id;
1820 $mod->section = 0;
1821 if (! $mod->coursemodule = add_course_module($mod) ) { // assumes course/lib.php is loaded
33e21153 1822 notify("Could not add a new course module to the course '$course->fullname'");
e1b5643f 1823 return false;
1824 }
1825 if (! $sectionid = add_mod_to_section($mod) ) { // assumes course/lib.php is loaded
1826 notify("Could not add the new course module to that section");
1827 return false;
1828 }
1829 if (! set_field("course_modules", "section", $sectionid, "id", $mod->coursemodule)) {
1830 notify("Could not update the course module with the correct section");
1831 return false;
1832 }
1833 include_once("$CFG->dirroot/course/lib.php");
1834 rebuild_course_cache($courseid);
65b0e537 1835
8daaf761 1836 return get_record("forum", "id", "$forum->id");
82aa0e8d 1837}
1838
f93f848a 1839
65b0e537 1840function forum_make_mail_post(&$post, $user, $touser, $course,
11b0c469 1841 $ownpost=false, $reply=false, $link=false, $rate=false, $footer="") {
2b63df96 1842
ee8e0008 1843 // Given the data about a posting, builds up the HTML to display it and
1844 // returns the HTML in a string. This is designed for sending via HTML email.
501cdbd8 1845
15f81ee3 1846 global $CFG, $USER;
501cdbd8 1847
0d851f90 1848 static $formattedtext; // Cached version of formatted text for a post
1849 static $formattedtextid; // The ID number of the post
1850
ee8e0008 1851 $post->forum = get_field('forum_discussions', 'forum', 'id', $post->discussion);
2b63df96 1852
ee8e0008 1853 if (!$cm = get_coursemodule_from_instance('forum', $post->forum)) {
2a692058 1854 mtrace('Course Module ID was incorrect');
7613e6d7 1855 }
1856 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
1857
1858
0d851f90 1859 if (empty($formattedtextid) or $formattedtextid != $post->id) { // Recalculate the formatting
326ce3c4 1860 $options = new Object;
1861 $options->para = true;
f2b5d7e3 1862 $formattedtext = format_text(trusttext_strip($post->message), $post->format, $options, $course->id);
0d851f90 1863 $formattedtextid = $post->id;
1864 }
1865
add3201e 1866 $output = '<table border="0" cellpadding="3" cellspacing="0" class="forumpost">';
501cdbd8 1867
add3201e 1868 $output .= '<tr class="header"><td width="35" valign="top" class="picture left">';
501cdbd8 1869 $output .= print_user_picture($user->id, $course->id, $user->picture, false, true);
add3201e 1870 $output .= '</td>';
501cdbd8 1871
1872 if ($post->parent) {
add3201e 1873 $output .= '<td class="topic">';
501cdbd8 1874 } else {
add3201e 1875 $output .= '<td class="topic starter">';
501cdbd8 1876 }
add3201e 1877 $output .= '<div class="subject">'.format_string($post->subject).'</div>';
1b26d5e7 1878
15f81ee3 1879 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $modcontext));
add3201e 1880 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
1881 $by->date = userdate($post->modified, '', $touser->timezone);
1882 $output .= '<div class="author">'.get_string('bynameondate', 'forum', $by).'</div>';
1883
1884 $output .= '</td></tr>';
1885
7b54f563 1886 $output .= '<tr><td class="left side" valign="top">';
add3201e 1887 if ($group = user_group($course->id, $user->id)) {
f393f545 1888 $output .= print_group_picture($group, $course->id, false, true, true);
add3201e 1889 } else {
1890 $output .= '&nbsp;';
1891 }
1b26d5e7 1892
add3201e 1893 $output .= '</td><td class="content">';
501cdbd8 1894
7f6689e4 1895 if ($post->attachment) {
1896 $post->course = $course->id;
add3201e 1897 $output .= '<div class="attachments">';
1898 $output .= forum_print_attachments($post, 'html');
72d497d4 1899 $output .= "</div>";
7f6689e4 1900 }
1901
0d851f90 1902 $output .= $formattedtext;
501cdbd8 1903
add3201e 1904/// Commands
add3201e 1905 $commands = array();
501cdbd8 1906
2e2e71a8 1907 if ($post->parent) {
add3201e 1908 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
1909 $post->discussion.'&amp;parent='.$post->parent.'">'.get_string('parent', 'forum').'</a>';
2e2e71a8 1910 }
ce45515e 1911
add3201e 1912 if ($reply) {
1913 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.
1914 get_string('reply', 'forum').'</a>';
501cdbd8 1915 }
1916
add3201e 1917 $output .= '<div class="commands">';
1918 $output .= implode(' | ', $commands);
1919 $output .= '</div>';
1920
add3201e 1921/// Context link to post if required
501cdbd8 1922 if ($link) {
add3201e 1923 $output .= '<div class="link">';
0be4d8bf 1924 $output .= '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#p'.$post->id.'">'.
2b63df96 1925 get_string('postincontext', 'forum').'</a>';
add3201e 1926 $output .= '</div>';
501cdbd8 1927 }
add3201e 1928
501cdbd8 1929 if ($footer) {
add3201e 1930 $output .= '<div class="footer">'.$footer.'</div>';
501cdbd8 1931 }
add3201e 1932 $output .= '</td></tr></table>'."\n\n";
1933
501cdbd8 1934 return $output;
1935}
1936
1937
65b0e537 1938function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link=false,
f37da850 1939 $ratings=NULL, $footer="", $highlight="", $post_read=-99) {
74f5d1e3 1940
098d27d4 1941 global $USER, $CFG, $SESSION;
501cdbd8 1942
951e1073 1943 static $stredit, $strdelete, $strreply, $strparent, $strprune;
1944 static $strpruneheading, $threadedmode;
77efef3e 1945 static $strmarkread, $strmarkunread, $istracked;
f37da850 1946
951e1073 1947
87ca0adf 1948 $discussion = get_record('forum_discussions', 'id', $post->discussion);
951e1073 1949 if (!$cm = get_coursemodule_from_instance('forum', $discussion->forum)) {
1950 error('Course Module ID was incorrect');
1951 }
1952 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
1953
1954
098d27d4 1955 if (!forum_user_can_see_post($post->forum,$post->discussion,$post)) {
1956 if (empty($SESSION->forum_search)) {
1957 // just viewing, return
1958 return;
2b63df96 1959 }
0be4d8bf 1960 echo '<a id="p'.$post->id.'"></a>';
098d27d4 1961 echo '<table cellspacing="0" class="forumpost">';
1962 echo '<tr class="header"><td class="picture left">';
1963 // print_user_picture($post->userid, $courseid, $post->picture);
1964 echo '</td>';
1965 if ($post->parent) {
1966 echo '<td class="topic">';
1967 } else {
1968 echo '<td class="topic starter">';
1969 }
1970 echo '<div class="subject">'.get_string('forumsubjecthidden','forum').'</div>';
1971 echo '<div class="author">';
1972 print_string('forumauthorhidden','forum');
1973 echo '</div></td></tr>';
2b63df96 1974
098d27d4 1975 echo '<tr><td class="left side">';
1976 echo '&nbsp;';
2b63df96 1977
098d27d4 1978 /// Actual content
2b63df96 1979
098d27d4 1980 echo '</td><td class="content">'."\n";
1981 echo get_string('forumbodyhidden','forum');
1982 echo '</td></tr></table>';
1983 return;
1984 }
1985
2e2e71a8 1986 if (empty($stredit)) {
359f2758 1987 $stredit = get_string('edit', 'forum');
1988 $strdelete = get_string('delete', 'forum');
1989 $strreply = get_string('reply', 'forum');
1990 $strparent = get_string('parent', 'forum');
1991 $strpruneheading = get_string('pruneheading', 'forum');
d494dd83 1992 $strprune = get_string('prune', 'forum');
2e2e71a8 1993 $threadedmode = (!empty($USER->mode) and ($USER->mode == FORUM_MODE_THREADED));
f37da850 1994 $strmarkread = get_string('markread', 'forum');
1995 $strmarkunread = get_string('markunread', 'forum');
77efef3e 1996
1997 if (!empty($post->forum)) {
2b63df96 1998 $istracked = (forum_tp_can_track_forums($post->forum) &&
77efef3e 1999 forum_tp_is_tracked($post->forum));
2000 } else {
2001 $istracked = false;
2002 }
f37da850 2003 }
2004
eaf50aef 2005 if ($istracked) {
f37da850 2006 if ($post_read == -99) { // If we don't know yet...
489de4ae 2007 /// The front page can display a news item post to non-logged in users. This should
2008 /// always appear as 'read'.
2009 $post_read = empty($USER) || forum_tp_is_post_read($USER->id, $post);
f37da850 2010 }
2011 if ($post_read) {
2012 $read_style = ' read';
2013 } else {
2014 $read_style = ' unread';
2015 echo '<a name="unread"></a>';
2016 }
2017 } else {
2018 $read_style = '';
2e2e71a8 2019 }
2020
0be4d8bf 2021 echo '<a id="p'.$post->id.'"></a>';
33200577 2022 echo '<table cellspacing="0" class="forumpost'.$read_style.'">';
501cdbd8 2023
d3583b41 2024 echo '<tr class="header"><td class="picture left">';
501cdbd8 2025 print_user_picture($post->userid, $courseid, $post->picture);
d3583b41 2026 echo '</td>';
501cdbd8 2027
2028 if ($post->parent) {
d3583b41 2029 echo '<td class="topic">';
501cdbd8 2030 } else {
d3583b41 2031 echo '<td class="topic starter">';
501cdbd8 2032 }
83ec9098 2033
47c9c8f5 2034 echo '<div class="subject">'.format_string($post->subject).'</div>';
e3ff14ca 2035
d3583b41 2036 echo '<div class="author">';
951e1073 2037 $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
d3583b41 2038 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
2039 $post->userid.'&amp;course='.$courseid.'">'.$fullname.'</a>';
d62413e8 2040 $by->date = userdate($post->modified);
d3583b41 2041 print_string('bynameondate', 'forum', $by);
2042 echo '</div></td></tr>';
1b26d5e7 2043
d3583b41 2044 echo '<tr><td class="left side">';
507407a7 2045 if ($group = user_group($courseid, $post->userid)) {
a4fbb0b2 2046 print_group_picture($group, $courseid, false, false, true);
507407a7 2047 } else {
d3583b41 2048 echo '&nbsp;';
507407a7 2049 }
d3583b41 2050
2051/// Actual content
2052
2053 echo '</td><td class="content">'."\n";
501cdbd8 2054
7f6689e4 2055 if ($post->attachment) {
2056 $post->course = $courseid;
d3583b41 2057 $post->forum = get_field('forum_discussions', 'forum', 'id', $post->discussion);
2058 echo '<div class="attachments">';
72d497d4 2059 $attachedimages = forum_print_attachments($post);
d3583b41 2060 echo '</div>';
e9c2dc1f 2061 } else {
d3583b41 2062 $attachedimages = '';
7f6689e4 2063 }
2064
d3583b41 2065
326ce3c4 2066 $options = new Object;
2067 $options->para = false;
f2b5d7e3 2068 $options->trusttext = true;
5be7800c 2069 if ($link and (strlen(strip_tags($post->message)) > $CFG->forum_longpost)) {
aa153f29 2070 // Print shortened version
326ce3c4 2071 echo format_text(forum_shorten_post($post->message), $post->format, $options, $courseid);
c585fa17 2072 $numwords = count_words(strip_tags($post->message));
d3583b41 2073 echo '<p><a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
2074 echo get_string('readtherest', 'forum');
2075 echo '</a> ('.get_string('numwords', '', $numwords).')...</p>';
501cdbd8 2076 } else {
aa153f29 2077 // Print whole message
88438a58 2078 if ($highlight) {
326ce3c4 2079 echo highlight($highlight, format_text($post->message, $post->format, $options, $courseid));
88438a58 2080 } else {
326ce3c4 2081 echo format_text($post->message, $post->format, $options, $courseid);
88438a58 2082 }
65b0e537 2083 echo $attachedimages;
501cdbd8 2084 }
2085
d3583b41 2086
2087/// Commands
2088
359f2758 2089 $commands = array();
501cdbd8 2090
eaf50aef 2091 if ($istracked) {
489de4ae 2092 /// SPECIAL CASE: The front page can display a news item post to non-logged in users.
2093 /// Don't display the mark read / unread controls in this case.
2094 if ($CFG->forum_usermarksread && !empty($USER)) {
f37da850 2095 if ($post_read) {
2096 $mcmd = '&amp;mark=unread&amp;postid='.$post->id;
2097 $mtxt = $strmarkunread;
2098 } else {
2099 $mcmd = '&amp;mark=read&amp;postid='.$post->id;
2100 $mtxt = $strmarkread;
2101 }
2102 if ($threadedmode) {
d3583b41 2103 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2104 $post->discussion.'&amp;parent='.$post->id.$mcmd.'">'.$mtxt.'</a>';
f37da850 2105 } else {
d3583b41 2106 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
0be4d8bf 2107 $post->discussion.$mcmd.'#p'.$post->id.'">'.$mtxt.'</a>';
f37da850 2108 }
2109 }
2110 }
2111
2e2e71a8 2112 if ($post->parent) {
2113 if ($threadedmode) {
d3583b41 2114 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2115 $post->discussion.'&amp;parent='.$post->parent.'">'.$strparent.'</a>';
2e2e71a8 2116 } else {
d3583b41 2117 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
0be4d8bf 2118 $post->discussion.'#p'.$post->parent.'">'.$strparent.'</a>';
2e2e71a8 2119 }
2120 }
2121
66035aaf 2122 $forumtype = get_field('forum', 'type', 'id', $post->forum);
2b63df96 2123
501cdbd8 2124 $age = time() - $post->created;
fbc21e82 2125 /// Hack for allow to edit news posts those are not displayed yet until they are displayed
2126 if (!$post->parent
66035aaf 2127 && $forumtype == 'news'
fbc21e82 2128 && get_field_sql("SELECT id FROM {$CFG->prefix}forum_discussions WHERE id = $post->discussion AND timestart > ".time())) {
2129 $age = 0;
2130 }
951e1073 2131 $editanypost = has_capability('mod/forum:editanypost', $modcontext);
9fbccd39 2132
6e372b25 2133
2134
a4ea3ef3 2135 if ($ownpost or $editanypost) {
951e1073 2136 if (($age < $CFG->maxeditingtime) or $editanypost) {
d3583b41 2137 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?edit='.$post->id.'">'.$stredit.'</a>';
501cdbd8 2138 }
64eacd6f 2139 }
aaf7a9dc 2140
66035aaf 2141 if (has_capability('mod/forum:splitdiscussions', $modcontext)
2142 && $post->parent && $forumtype != 'single') {
2143
d3583b41 2144 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?prune='.$post->id.
2145 '" title="'.$strpruneheading.'">'.$strprune.'</a>';
cf84431b 2146 }
aaf7a9dc 2147
9fbccd39 2148 if (($ownpost and $age < $CFG->maxeditingtime
2149 and has_capability('mod/forum:deleteownpost', $modcontext))
2150 or has_capability('mod/forum:deleteanypost', $modcontext)) {
d3583b41 2151 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?delete='.$post->id.'">'.$strdelete.'</a>';
64eacd6f 2152 }
359f2758 2153
a4ea3ef3 2154 if ($reply) {
d3583b41 2155 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.$strreply.'</a>';
501cdbd8 2156 }
501cdbd8 2157
d3583b41 2158 echo '<div class="commands">';
2159 echo implode(' | ', $commands);
2160 echo '</div>';
2161
2162
2163/// Ratings
74f5d1e3 2164
2165 $ratingsmenuused = false;
02ebf404 2166 if (!empty($ratings) and !empty($USER->id)) {
d3583b41 2167 echo '<div class="ratings">';
98914efd 2168 $useratings = true;
2169 if ($ratings->assesstimestart and $ratings->assesstimefinish) {
2170 if ($post->created < $ratings->assesstimestart or $post->created > $ratings->assesstimefinish) {
2171 $useratings = false;
2172 }
2173 }
2174 if ($useratings) {
3bd98ad4 2175 $mypost = ($USER->id == $post->userid);
2b63df96 2176
951e1073 2177 $canviewallratings = has_capability('mod/forum:viewanyrating', $modcontext);
2b63df96 2178
2179 if ($canviewallratings and !$mypost) {
951e1073 2180 forum_print_ratings_mean($post->id, $ratings->scale, $canviewallratings);
d395046a 2181 if (!empty($ratings->allow)) {
d3583b41 2182 echo '&nbsp;';
d395046a 2183 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
2184 $ratingsmenuused = true;
2185 }
3bd98ad4 2186
2187 } else if ($mypost) {
2188 forum_print_ratings_mean($post->id, $ratings->scale, true);
2189
98914efd 2190 } else if (!empty($ratings->allow) ) {
2191 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
74f5d1e3 2192 $ratingsmenuused = true;
2a3cda19 2193 }
501cdbd8 2194 }
d3583b41 2195 echo '</div>';
501cdbd8 2196 }
65b0e537 2197
d3583b41 2198/// Link to post if required
2199
501cdbd8 2200 if ($link) {
d3583b41 2201 echo '<div class="link">';
501cdbd8 2202 if ($post->replies == 1) {
d3583b41 2203 $replystring = get_string('repliesone', 'forum', $post->replies);
501cdbd8 2204 } else {
d3583b41 2205 $replystring = get_string('repliesmany', 'forum', $post->replies);
501cdbd8 2206 }
d3583b41 2207 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">'.
2208 get_string('discussthistopic', 'forum').'</a>&nbsp;('.$replystring.')';
2209 echo '</div>';
501cdbd8 2210 }
d3583b41 2211
501cdbd8 2212 if ($footer) {
d3583b41 2213 echo '<div class="footer">'.$footer.'</div>';
501cdbd8 2214 }
d3583b41 2215 echo '</td></tr></table>'."\n\n";
74f5d1e3 2216
eaf50aef 2217 if ($istracked && !$CFG->forum_usermarksread && !empty($post->forum)) {
f37da850 2218 forum_tp_mark_post_read($USER->id, $post, $post->forum);
2219 }
2220
74f5d1e3 2221 return $ratingsmenuused;
501cdbd8 2222}
42fb3c85 2223
2224
eaf50aef 2225/**
2226* This function prints the overview of a discussion in the forum listing.
2227* It needs some discussion information and some post information, these
2228* happen to be combined for efficiency in the $post parameter by the function
2229* that calls this one: forum_print_latest_discussions()
2b63df96 2230*
eaf50aef 2231* @param object $post The post object (passed by reference for speed).
2232* @param object $forum The forum object.
2233* @param int $group Current group.
2234* @param string $datestring Format to use for the dates.
2235* @param boolean $cantrack Is tracking enabled for this forum.
2236* @param boolean $forumtracked Is the user tracking this forum.
2237*/
951e1073 2238function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring="",
2239 $cantrack=true, $forumtracked=true) {
43921b8a 2240
d30867b0 2241 global $USER, $CFG;
3335f6fb 2242
f51e8d7e 2243 static $rowcount;
5733262d 2244 static $strmarkalldread;
f51e8d7e 2245
2b63df96 2246
951e1073 2247 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
2248 error('Course Module ID was incorrect');
2249 }
2250 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2b63df96 2251
951e1073 2252
f51e8d7e 2253 if (!isset($rowcount)) {
2254 $rowcount = 0;
5733262d 2255 $strmarkalldread = get_string('markalldread', 'forum');
f51e8d7e 2256 } else {
2257 $rowcount = ($rowcount + 1) % 2;
2258 }
2259
17dc3f3c 2260 $post->subject = format_string($post->subject,true);
436a7cae 2261
f51e8d7e 2262 echo "\n\n";
2263 echo '<tr class="discussion r'.$rowcount.'">';
3335f6fb 2264
29507631 2265 // Topic
f51e8d7e 2266 echo '<td class="topic starter">';
2267 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">'.$post->subject.'</a>';
29507631 2268 echo "</td>\n";
2269
2270 // Picture
f51e8d7e 2271 echo '<td class="picture">';
a796d0b8 2272 print_user_picture($post->userid, $forum->course, $post->picture);
29507631 2273 echo "</td>\n";
3335f6fb 2274
29507631 2275 // User name
951e1073 2276 $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
f51e8d7e 2277 echo '<td class="author">';
2278 echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->userid.'&amp;course='.$forum->course.'">'.$fullname.'</a>';
29507631 2279 echo "</td>\n";
2280
3a68fbbb 2281 // Group picture
425b4f1a 2282 if ($group !== -1) { // Groups are active - group is a group data object or NULL
f51e8d7e 2283 echo '<td class="picture group">';
c2b552fe 2284 if (!empty($group->picture) and empty($group->hidepicture)) {
3a68fbbb 2285 print_group_picture($group, $forum->course, false, false, true);
2286 } else if (isset($group->id)) {
fa22fd5f 2287 echo '<a href="'.$CFG->wwwroot.'/user/index.php?id='.$forum->course.'&amp;group='.$group->id.'">'.$group->name.'</a>';
3a68fbbb 2288 }
2289 echo "</td>\n";
2290 }
2291
f0da6b85 2292 if (has_capability('mod/forum:viewdiscussion', $modcontext)) { // Show the column with replies
f51e8d7e 2293 echo '<td class="replies">';
2294 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
2295 echo $post->replies.'</a>';
a796d0b8 2296 echo "</td>\n";
e3ff14ca 2297
eaf50aef 2298 if ($cantrack) {
f51e8d7e 2299 echo '<td class="replies">';
eaf50aef 2300 if ($forumtracked) {
2301 if ($post->unread > 0) {
2302 echo '<span class="unread">';
2303 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#unread">';
2304 echo $post->unread;
2305 echo '</a>';
c39748f4 2306 echo '<a title="'.$strmarkalldread.'" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
eaf50aef 2307 $forum->id.'&amp;d='.$post->discussion.'&amp;mark=read&amp;returnpage=view.php">' .
0d905d9f 2308 '<img src="'.$CFG->pixpath.'/t/clear.gif" class="iconsmall" alt="'.$strmarkalldread.'" /></a>';
eaf50aef 2309 echo '</span>';
2310 } else {
2311 echo '<span class="read">';
eaf50aef 2312 echo $post->unread;
eaf50aef 2313 echo '</span>';
2314 }
f51e8d7e 2315 } else {
343af274 2316 echo '<span class="read">';
eaf50aef 2317 echo '-';
343af274 2318 echo '</span>';
3a68fbbb 2319 }
f37da850 2320 echo "</td>\n";
2321 }
a796d0b8 2322 }
3335f6fb 2323
f51e8d7e 2324 echo '<td class="lastpost">';
43921b8a 2325 $usedate = (empty($post->timemodified)) ? $post->modified : $post->timemodified; // Just in case
839f2456 2326 $parenturl = (empty($post->lastpostid)) ? '' : '&amp;parent='.$post->lastpostid;
098d27d4 2327 $usermodified->id = $post->usermodified;
268c6485 2328 $usermodified->firstname = $post->umfirstname;
2329 $usermodified->lastname = $post->umlastname;
f51e8d7e 2330 echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->usermodified.'&amp;course='.$forum->course.'">'.
2331 fullname($usermodified).'</a><br />';
ac00b904 2332 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.$parenturl.'">'.
43921b8a 2333 userdate($usedate, $datestring).'</a>';
29507631 2334 echo "</td>\n";
2335
f51e8d7e 2336 echo "</tr>\n\n";
3335f6fb 2337
3335f6fb 2338}
2339
2340
aa153f29 2341function forum_shorten_post($message) {
c585fa17 2342// Given a post object that we already know has a long message
65b0e537 2343// this function truncates the message nicely to the first
5be7800c 2344// sane place between $CFG->forum_longpost and $CFG->forum_shortpost
2345
2346 global $CFG;
c585fa17 2347
2348 $i = 0;
2349 $tag = false;
2350 $length = strlen($message);
2351 $count = 0;
2352 $stopzone = false;
2353 $truncate = 0;
2354
2355 for ($i=0; $i<$length; $i++) {
a8afb411 2356 $char = $message[$i];
c585fa17 2357
2358 switch ($char) {
65b0e537 2359 case "<":
c585fa17 2360 $tag = true;
2361 break;
65b0e537 2362 case ">":
c585fa17 2363 $tag = false;
2364 break;
2365 default:
2366 if (!$tag) {
2367 if ($stopzone) {
67f0b4cc 2368 if ($char == ".") {
a8afb411 2369 $truncate = $i+1;
c585fa17 2370 break 2;
2371 }
2372 }
2373 $count++;
2374 }
a8afb411 2375 break;
c585fa17 2376 }
2377 if (!$stopzone) {
5be7800c 2378 if ($count > $CFG->forum_shortpost) {
c585fa17 2379 $stopzone = true;
2380 }
2381 }
2382 }
aa153f29 2383
c585fa17 2384 if (!$truncate) {
a8afb411 2385 $truncate = $i;
c585fa17 2386 }
2387
67f0b4cc 2388 return substr($message, 0, $truncate);
aa153f29 2389}
2390
501cdbd8 2391
3bd98ad4 2392function forum_print_ratings_mean($postid, $scale, $link=true) {
02ebf404 2393/// Print the multiple ratings on a post given to the current user by others.
2394/// Scale is an array of ratings
2395
2396 static $strrate;
05c47ef7 2397
2398 $mean = forum_get_ratings_mean($postid, $scale);
65b0e537 2399
05c47ef7 2400 if ($mean !== "") {
02ebf404 2401
2402 if (empty($strratings)) {
2403 $strratings = get_string("ratings", "forum");
501cdbd8 2404 }
501cdbd8 2405
02ebf404 2406 echo "$strratings: ";
3bd98ad4 2407 if ($link) {
2408 link_to_popup_window ("/mod/forum/report.php?id=$postid", "ratings", $mean, 400, 600);
2409 } else {
2410 echo "$mean ";
2411 }
501cdbd8 2412 }
2413}
2414
501cdbd8 2415
0761d83f 2416function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {
2417/// Return the mean rating of a post given to the current user by others.
02ebf404 2418/// Scale is an array of possible ratings in the scale
2419/// Ratings is an optional simple array of actual ratings (just integers)
2420
2421 if (!$ratings) {
2422 $ratings = array();
2423 if ($rates = get_records("forum_ratings", "post", $postid)) {
2424 foreach ($rates as $rate) {
2425 $ratings[] = $rate->rating;
2426 }
501cdbd8 2427 }
501cdbd8 2428 }
02ebf404 2429
0761d83f 2430 $count = count($ratings);
2431
2432 if ($count == 0) {
02ebf404 2433 return "";
02ebf404 2434
0761d83f 2435 } else if ($count == 1) {
2436 return $scale[$ratings[0]];
2437
02ebf404 2438 } else {
0761d83f 2439 $total = 0;
2440 foreach ($ratings as $rating) {
2441 $total += $rating;
2442 }
2443 $mean = round( ((float)$total/(float)$count) + 0.001); // Little fudge factor so that 0.5 goes UP
65b0e537 2444
0761d83f 2445 if (isset($scale[$mean])) {
2446 return $scale[$mean]." ($count)";
2447 } else {
2448 return "$mean ($count)"; // Should never happen, hopefully
2449 }
02ebf404 2450 }
2451}
2452
2453function forum_get_ratings_summary($postid, $scale, $ratings=NULL) {
2454/// Return a summary of post ratings given to the current user by others.
2455/// Scale is an array of possible ratings in the scale
2456/// Ratings is an optional simple array of actual ratings (just integers)
2457
2458 if (!$ratings) {
2459 $ratings = array();
2460 if ($rates = get_records("forum_ratings", "post", $postid)) {
2461 foreach ($rates as $rate) {
2462 $rating[] = $rate->rating;
2463 }
2464 }
2465 }
2466
2467
2468 if (!$count = count($ratings)) {
2469 return "";
2470 }
2471
2472
2473 foreach ($scale as $key => $scaleitem) {
2474 $sumrating[$key] = 0;
2475 }
2476
2477 foreach ($ratings as $rating) {
2478 $sumrating[$rating]++;
2479 }
2480
2481 $summary = "";
2482 foreach ($scale as $key => $scaleitem) {
2483 $summary = $sumrating[$key].$summary;
2484 if ($key > 1) {
2485 $summary = "/$summary";
2486 }
2487 }
2488 return $summary;
2489}
2490
2491function forum_print_rating_menu($postid, $userid, $scale) {
65b0e537 2492/// Print the menu of ratings as part of a larger form.
02ebf404 2493/// If the post has already been - set that value.
2494/// Scale is an array of ratings
2495
2496 static $strrate;
2497
2498 if (!$rating = get_record("forum_ratings", "userid", $userid, "post", $postid)) {
1a7cdb11 2499 $rating->rating = FORUM_UNSET_POST_RATING;
02ebf404 2500 }
2501
2502 if (empty($strrate)) {
2503 $strrate = get_string("rate", "forum");
2504 }
1a7cdb11 2505 $scale = array(FORUM_UNSET_POST_RATING => $strrate.'...') + $scale;
2506 choose_from_menu($scale, $postid, $rating->rating, '');
501cdbd8 2507}
2508
83da3d28 2509/**
2510 * Print the drop down that allows the user to select how they want to have
2511 * the discussion displayed.
2512 * @param $id - forum id if $forumtype is 'single',
2513 * discussion id for any other forum type
2514 * @param $mode - forum layout mode
2515 * @param $forumtype - optional
2516 */
2517function forum_print_mode_form($id, $mode, $forumtype='') {
f0ef40c5 2518 global $FORUM_LAYOUT_MODES;
501cdbd8 2519
83da3d28 2520 if ($forumtype == 'single') {
2521 popup_form("view.php?f=$id&amp;mode=", $FORUM_LAYOUT_MODES, "mode", $mode, "");
2522 } else {
2523 popup_form("discuss.php?d=$id&amp;mode=", $FORUM_LAYOUT_MODES, "mode", $mode, "");
2524 }
501cdbd8 2525}
2526
6f1cc8d6 2527function forum_search_form($course, $search='') {
501cdbd8 2528 global $CFG;
2529
81d22774 2530 $output = '<div class="forumsearch">';
2531 $output .= '<form action="'.$CFG->wwwroot.'/mod/forum/search.php" style="display:inline">';
d69e9c15 2532 $output .= '<fieldset class="invisiblefieldset">';
bbbf2d40 2533 $output .= helpbutton('search', get_string('search'), 'moodle', true, false, '', true);
6f1cc8d6 2534 $output .= '<input name="search" type="text" size="18" value="'.$search.'" alt="search" />';
2535 $output .= '<input value="'.get_string('searchforums', 'forum').'" type="submit" />';
2536 $output .= '<input name="id" type="hidden" value="'.$course->id.'" />';
81d22774 2537 $output .= '</fieldset>';
6f1cc8d6 2538 $output .= '</form>';
81d22774 2539 $output .= '</div>';
5e367a2d 2540
6f1cc8d6 2541 return $output;
501cdbd8 2542}
2543
2544
11b0c469 2545function forum_set_return() {
607809b3 2546 global $CFG, $SESSION;
501cdbd8 2547
28e1e8b9 2548 if (! isset($SESSION->fromdiscussion)) {
48d38fad 2549 if (!empty($_SERVER['HTTP_REFERER'])) {
2550 $referer = $_SERVER['HTTP_REFERER'];
2551 } else {
2552 $referer = "";
2553 }
28e1e8b9 2554 // If the referer is NOT a login screen then save it.
48d38fad 2555 if (! strncasecmp("$CFG->wwwroot/login", $referer, 300)) {
607809b3 2556 $SESSION->fromdiscussion = $_SERVER["HTTP_REFERER"];
28e1e8b9 2557 }
501cdbd8 2558 }
2559}
2560
2561
11b0c469 2562function forum_go_back_to($default) {
501cdbd8 2563 global $SESSION;
2564
9c9f7d77 2565 if (!empty($SESSION->fromdiscussion)) {
501cdbd8 2566 $returnto = $SESSION->fromdiscussion;
2567 unset($SESSION->fromdiscussion);
2568 return $returnto;
2569 } else {
2570 return $default;
2571 }
2572}
2573
7f6689e4 2574function forum_file_area_name($post) {
2575// Creates a directory file name, suitable for make_upload_directory()
2576 global $CFG;
2577
2578 return "$post->course/$CFG->moddata/forum/$post->forum/$post->id";
2579}
2580
2581function forum_file_area($post) {
2582 return make_upload_directory( forum_file_area_name($post) );
2583}
2584
2585function forum_delete_old_attachments($post, $exception="") {
2586// Deletes all the user files in the attachments area for a post
2587// EXCEPT for any file named $exception
2588
2589 if ($basedir = forum_file_area($post)) {
2590 if ($files = get_directory_list($basedir)) {
2591 foreach ($files as $file) {
2592 if ($file != $exception) {
2593 unlink("$basedir/$file");
2594 notify("Existing file '$file' has been deleted!");
2595 }
2596 }
2597 }
2598 if (!$exception) { // Delete directory as well, if empty
2599 rmdir("$basedir");
2600 }
2601 }
2602}
2603
cc2b7ea5 2604function forum_move_attachments($discussion, $forumid) {
65b0e537 2605/// Given a discussion object that is being moved to forumid,
2606/// this function checks all posts in that discussion
2607/// for attachments, and if any are found, these are
cc2b7ea5 2608/// moved to the new forum directory.
2609
2610 global $CFG;
2611
18b8fbfa 2612 require_once($CFG->dirroot.'/lib/uploadlib.php');
2613
cc2b7ea5 2614 $return = true;
2615
2616 if ($posts = get_records_select("forum_posts", "discussion = '$discussion->id' AND attachment <> ''")) {
2617 foreach ($posts as $oldpost) {
2618 $oldpost->course = $discussion->course;
2619 $oldpost->forum = $discussion->forum;
2620 $oldpostdir = "$CFG->dataroot/".forum_file_area_name($oldpost);
2621 if (is_dir($oldpostdir)) {
2622 $newpost = $oldpost;
2623 $newpost->forum = $forumid;
03c9562b 2624 $newpostdir = forum_file_area_name($newpost);
2625 // take off the last directory because otherwise we're renaming to a directory that already exists
2626 // and this is unhappy in certain situations, eg over an nfs mount and potentially on windows too.
2627 make_upload_directory(substr($newpostdir,0,strrpos($newpostdir,'/')));
2628 $newpostdir = $CFG->dataroot.'/'.forum_file_area_name($newpost);
18b8fbfa 2629 $files = get_directory_list($oldpostdir); // get it before we rename it.
cc2b7ea5 2630 if (! @rename($oldpostdir, $newpostdir)) {
2631 $return = false;
2632 }
18b8fbfa 2633 foreach ($files as $file) {
2634 clam_change_log($oldpostdir.'/'.$file,$newpostdir.'/'.$file);
2635 }
cc2b7ea5 2636 }
2637 }
2638 }
2639 return $return;
2640}
2641
7f6689e4 2642function forum_print_attachments($post, $return=NULL) {
2643// if return=html, then return a html string.
2644// if return=text, then return a text-only string.
72d497d4 2645// otherwise, print HTML for non-images, and return image HTML
7f6689e4 2646
2647 global $CFG;
2648
2649 $filearea = forum_file_area_name($post);
2650
72d497d4 2651 $imagereturn = "";
2652 $output = "";
2653
7f6689e4 2654 if ($basedir = forum_file_area($post)) {
2655 if ($files = get_directory_list($basedir)) {
2656 $strattachment = get_string("attachment", "forum");
2657 foreach ($files as $file) {
2658 $icon = mimeinfo("icon", $file);
feaf5d06 2659 $type = mimeinfo("type", $file);
7f6689e4 2660 if ($CFG->slasharguments) {
2a1975cb 2661 $ffurl = "$CFG->wwwroot/file.php/$filearea/$file";
7f6689e4 2662 } else {
2a1975cb 2663 $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
7f6689e4 2664 }
0d905d9f 2665 $image = "<img src=\"$CFG->pixpath/f/$icon\" class=\"icon\" alt=\"\" />";
7f6689e4 2666
2667 if ($return == "html") {
2a1975cb 2668 $output .= "<a href=\"$ffurl\">$image</a> ";
2669 $output .= "<a href=\"$ffurl\">$file</a><br />";
7f6689e4 2670
2671 } else if ($return == "text") {
2a1975cb 2672 $output .= "$strattachment $file:\n$ffurl\n";
7f6689e4 2673
2674 } else {
feaf5d06 2675 if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) { // Image attachments don't get printed as links
2a1975cb 2676 $imagereturn .= "<br /><img src=\"$ffurl\" alt=\"\" />";
72d497d4 2677 } else {
2a1975cb 2678 echo "<a href=\"$ffurl\">$image</a> ";
bce7a133 2679 echo filter_text("<a href=\"$ffurl\">$file</a><br />");
72d497d4 2680 }
7f6689e4 2681 }
2682 }
2683 }
2684 }
72d497d4 2685
7f6689e4 2686 if ($return) {
2687 return $output;
2688 }
72d497d4 2689
2690 return $imagereturn;
7f6689e4 2691}
db290a6e 2692/**
e3ff14ca 2693 * If successful, this function returns the name of the file
db290a6e 2694 * @param $post is a full post record, including course and forum
2695 * @param $newfile is a full upload array from $_FILES
2696 * @param $message is a string to hold the messages.
e3ff14ca 2697 */
7f6689e4 2698
db290a6e 2699function forum_add_attachment($post, $inputname,&$message) {
7f6689e4 2700
9dd0b378 2701 global $CFG;
2702
4909e176 2703 if (!$forum = get_record("forum", "id", $post->forum)) {
2704 return "";
2705 }
2706
2707 if (!$course = get_record("course", "id", $forum->course)) {
2708 return "";
2709 }
2710
5ddaa2e2 2711 require_once($CFG->dirroot.'/lib/uploadlib.php');
db290a6e 2712 $um = new upload_manager($inputname,true,false,$course,false,$forum->maxbytes,true,true);
5ddaa2e2 2713 $dir = forum_file_area_name($post);
2714 if ($um->process_file_uploads($dir)) {
db290a6e 2715 $message .= $um->get_errors();
5ddaa2e2 2716 return $um->get_new_filename();
7f6689e4 2717 }
db290a6e 2718 $message .= $um->get_errors();
feaf5d06 2719 return null;
7f6689e4 2720}
501cdbd8 2721
db290a6e 2722function forum_add_new_post($post,&$message) {
501cdbd8 2723
f37da850 2724 global $USER, $CFG;
e3ff14ca 2725
ffe11640 2726 $post->created = $post->modified = time();
501cdbd8 2727 $post->mailed = "0";
a56f0d60 2728 $post->userid = $USER->id;
7f6689e4 2729 $post->attachment = "";
2730
65b0e537 2731 if (! $post->id = insert_record("forum_posts", $post)) {
7f6689e4 2732 return false;
2733 }
2734
db290a6e 2735 if ($post->attachment = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 2736 set_field("forum_posts", "attachment", $post->attachment, "id", $post->id);
2737 }
29507631 2738
2739 // Update discussion modified date
2740 set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
016cd6af 2741 set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
65b0e537 2742
eaf50aef 2743 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 2744 forum_tp_mark_post_read($post->userid, $post, $post->forum);
2745 }
2746
7f6689e4 2747 return $post->id;
501cdbd8 2748}
2749
db290a6e 2750function forum_update_post($post,&$message) {
501cdbd8 2751
f37da850 2752 global $USER, $CFG;
a56f0d60 2753
ffe11640 2754 $post->modified = time();
0936de64 2755
0ab85112 2756 if (!$post->parent) { // Post is a discussion starter - update discussion title too
2757 set_field("forum_discussions", "name", $post->subject, "id", $post->discussion);
2758 }
29507631 2759
db290a6e 2760 if ($newfilename = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 2761 $post->attachment = $newfilename;
2762 } else {
2763 unset($post->attachment);
2764 }
29507631 2765
2766 // Update discussion modified date
2767 set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
016cd6af 2768 set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
29507631 2769
eaf50aef 2770 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 2771 forum_tp_mark_post_read($post->userid, $post, $post->forum);
2772 }
2773
ffe11640 2774 return update_record("forum_posts", $post);
501cdbd8 2775}
2776
db290a6e 2777function forum_add_discussion($discussion,&$message) {
65b0e537 2778// Given an object containing all the necessary data,
501cdbd8 2779// create a new discussion and return the id
2780
f37da850 2781 GLOBAL $USER, $CFG;
501cdbd8 2782
2783 $timenow = time();
2784
65b0e537 2785 // The first post is stored as a real post, and linked
501cdbd8 2786 // to from the discuss entry.
2787
2788 $post->discussion = 0;
2789 $post->parent = 0;
ebc3bd2b 2790 $post->userid = $USER->id;
501cdbd8 2791 $post->created = $timenow;
2792 $post->modified = $timenow;
2793 $post->mailed = 0;
2794 $post->subject = $discussion->name;
2795 $post->message = $discussion->intro;
7f6689e4 2796 $post->attachment = "";
2797 $post->forum = $discussion->forum;
2798 $post->course = $discussion->course;
9f0b8269 2799 $post->format = $discussion->format;
41547057 2800 $post->mailnow = $discussion->mailnow;
501cdbd8 2801
2802 if (! $post->id = insert_record("forum_posts", $post) ) {
2803 return 0;
2804 }
2805
db290a6e 2806 if ($post->attachment = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 2807 set_field("forum_posts", "attachment", $post->attachment, "id", $post->id); //ignore errors
2808 }
2809
65b0e537 2810 // Now do the main entry for the discussion,
02509fe6 2811 // linking to this first post
04eba58f 2812
caadf009 2813 $discussion->firstpost = $post->id;
2814 $discussion->timemodified = $timenow;
016cd6af 2815 $discussion->usermodified = $post->userid;
a56f0d60 2816 $discussion->userid = $USER->id;
04eba58f 2817
4e00a4d9 2818 if (! $post->discussion = insert_record("forum_discussions", $discussion) ) {
caadf009 2819 delete_records("forum_posts", "id", $post->id);
2820 return 0;
04eba58f 2821 }
2822
caadf009 2823 // Finally, set the pointer on the post.
4e00a4d9 2824 if (! set_field("forum_posts", "discussion", $post->discussion, "id", $post->id)) {
caadf009 2825 delete_records("forum_posts", "id", $post->id);
4e00a4d9 2826 delete_records("forum_discussions", "id", $post->discussion);
caadf009 2827 return 0;
04eba58f 2828 }
04eba58f 2829
eaf50aef 2830 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 2831 forum_tp_mark_post_read($post->userid, $post, $post->forum);
2832 }
2833
4e00a4d9 2834 return $post->discussion;
caadf009 2835}
04eba58f 2836
04eba58f 2837
e2c1dbe9 2838function forum_delete_discussion($discussion, $fulldelete=false) {
caadf009 2839// $discussion is a discussion record object
04eba58f 2840
2841 $result = true;
2842
caadf009 2843 if ($posts = get_records("forum_posts", "discussion", $discussion->id)) {
2844 foreach ($posts as $post) {
2845 $post->course = $discussion->course;
2846 $post->forum = $discussion->forum;
2847 if (! delete_records("forum_ratings", "post", "$post->id")) {
2848 $result = false;
2849 }
e2c1dbe9 2850 if (! forum_delete_post($post, $fulldelete)) {
04eba58f 2851 $result = false;
2852 }
2853 }
2854 }
2855
f37da850 2856 forum_tp_delete_read_records(-1, -1, $discussion->id);
2857
caadf009 2858 if (! delete_records("forum_discussions", "id", "$discussion->id")) {
04eba58f 2859 $result = false;
2860 }
2861
2862 return $result;
2863}
2864
2865
b82faacd 2866function forum_delete_post($post, $children=false) {
1da8c568 2867 if ($childposts = get_records('forum_posts', 'parent', $post->id)) {
2868 if ($children) {
b82faacd 2869 foreach ($childposts as $childpost) {
2870 forum_delete_post($childpost, true);
2871 }
1da8c568 2872 } else {
2873 return false;
b82faacd 2874 }
2875 }
caadf009 2876 if (delete_records("forum_posts", "id", $post->id)) {
2877 delete_records("forum_ratings", "post", $post->id); // Just in case
f37da850 2878
b82faacd 2879 forum_tp_delete_read_records(-1, $post->id);
f37da850 2880
caadf009 2881 if ($post->attachment) {
2882 $discussion = get_record("forum_discussions", "id", $post->discussion);
2883 $post->course = $discussion->course;
2884 $post->forum = $discussion->forum;
2885 forum_delete_old_attachments($post);
2886 }
1da8c568 2887
2888 /// Just in case we are deleting the last post
2889 forum_discussion_update_last_post($post->discussion);
2890
caadf009 2891 return true;
2892 }
2893 return false;
2894}
501cdbd8 2895
b82faacd 2896function forum_count_replies($post, $children=true) {
2897 $count = 0;
2898
2899 if ($children) {
2900 if ($childposts = get_records('forum_posts', 'parent', $post->id)) {
2901 foreach ($childposts as $childpost) {
2902 $count ++; // For this child
2903 $count += forum_count_replies($childpost, true);
2904 }
2905 }
2906 } else {
2907 $count += count_records('forum_posts', 'parent', $post->id);
2908 }
2909
2910 return $count;
2911}
2912
2913
501cdbd8 2914function forum_forcesubscribe($forumid, $value=1) {
2915 return set_field("forum", "forcesubscribe", $value, "id", $forumid);
2916}
2917
2918function forum_is_forcesubscribed($forumid) {
709f0ec8 2919 return (get_field("forum", "forcesubscribe", "id", $forumid) == 1);
501cdbd8 2920}
2921
2922function forum_is_subscribed($userid, $forumid) {
2923 if (forum_is_forcesubscribed($forumid)) {
2924 return true;
2925 }
ebc3bd2b 2926 return record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid);
86970225 2927}
2928
501cdbd8 2929function forum_subscribe($userid, $forumid) {
9fa49e22 2930/// Adds user to the subscriber list
2931
6673d7bd 2932 if (record_exists("forum_subscriptions", "userid", $userid, "forum", $forumid)) {
2933 return true;
2934 }
2935
ebc3bd2b 2936 $sub->userid = $userid;
9fa49e22 2937 $sub->forum = $forumid;
501cdbd8 2938
9fa49e22 2939 return insert_record("forum_subscriptions", $sub);
501cdbd8 2940}
2941
2942function forum_unsubscribe($userid, $forumid) {
9fa49e22 2943/// Removes user from the subscriber list
ebc3bd2b 2944 return delete_records("forum_subscriptions", "userid", $userid, "forum", $forumid);
501cdbd8 2945}
2946
0a9f61b5 2947function forum_post_subscription($post) {
2948/// Given a new post, subscribes or unsubscribes as appropriate.
2949/// Returns some text which describes what happened.
2950
2951 global $USER;
2952
2b63df96 2953 $subscribed=forum_is_subscribed($USER->id, $post->forum);
2954 if ((isset($post->subscribe) && $post->subscribe && $subscribed)
2955 || (!$post->subscribe && !$subscribed)) {
0a9f61b5 2956 return "";
2957 }
2958
2959 if (!$forum = get_record("forum", "id", $post->forum)) {
2960 return "";
2961 }
2962
067675c0 2963 $info->name = fullname($USER);
0a9f61b5 2964 $info->forum = $forum->name;
2965
2966 if (!empty($post->subscribe)) {
2967 forum_subscribe($USER->id, $post->forum);
2968 return "<p>".get_string("nowsubscribed", "forum", $info)."</p>";
2969 }
2970
2971 forum_unsubscribe($USER->id, $post->forum);
2972 return "<p>".get_string("nownotsubscribed", "forum", $info)."</p>";
2973}
2974
501cdbd8 2975
11b0c469 2976function forum_user_has_posted_discussion($forumid, $userid) {
d50704bf 2977 if ($discussions = forum_get_discussions($forumid, '', $userid)) {
501cdbd8 2978 return true;
2979 } else {
2980 return false;
2981 }
2982}
2983
dcd8e589 2984function forum_discussions_user_has_posted_in($forumid, $userid) {
2985 global $CFG;
2986
0b9873f2 2987 $haspostedsql = "SELECT d.id AS id,
dcd8e589 2988 d.*
f274fe07 2989 FROM {$CFG->prefix}forum_posts p,
2990 {$CFG->prefix}forum_discussions d
dcd8e589 2991 WHERE p.discussion = d.id
2992 AND d.forum = $forumid
2993 AND p.userid = $userid";
2994
2995 return get_records_sql($haspostedsql);
2996}
2997
bbbf2d40 2998function forum_user_has_posted($forumid, $did, $userid) {
098d27d4 2999 return record_exists('forum_posts','discussion',$did,'userid',$userid);
3000}
3001
918e9805 3002function forum_user_can_post_discussion($forum, $currentgroup=false, $groupmode=false, $cm=NULL, $context=NULL) {
501cdbd8 3003// $forum is an object
fa22fd5f 3004 global $USER, $SESSION;
bbbf2d40 3005
918e9805 3006 if (!$cm) {
3007 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
3008 error('Course Module ID was incorrect');
3009 }
3010 }
3011 if (!$context) {
3012 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
bbbf2d40 3013 }
bbbf2d40 3014
33e21153 3015 if (!has_capability('mod/forum:startdiscussion', $context)) {
bbbf2d40 3016 return false;
3017 }
3018
33e21153 3019 if ($forum->type == "eachuser") {
bbbf2d40 3020 return (!forum_user_has_posted_discussion($forum->id, $USER->id));
9197e147 3021 } else if ($currentgroup) {
0468976c 3022 return (has_capability('moodle/site:accessallgroups', $context)
f0da6b85 3023 or ismember($currentgroup));
501cdbd8 3024 } else {
fa22fd5f 3025 //else it might be group 0 in visible mode
3026 if ($groupmode == VISIBLEGROUPS){
f0da6b85 3027 return (ismember($currentgroup));
fa22fd5f 3028 }
3029 else {
f0da6b85 3030 return true;
fa22fd5f 3031 }
501cdbd8 3032 }
3033}
3034
bbbf2d40 3035/**
3036 * This function checks whether the user can reply to posts in a forum
3037 * discussion. Use forum_user_can_post_discussion() to check whether the user
3038 * can start dicussions.
3039 * @param $forum - forum object
3040 * @param $user - user object
3041 */
918e9805 3042function forum_user_can_post($forum, $user=NULL, $cm=NULL, $context=NULL) {
f690562f 3043
918e9805 3044 if (!$cm) {
3045 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
3046 error('Course Module ID was incorrect');
3047 }
3048 }
3049 if (!$context) {
3050 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
f690562f 3051 }
70c476a7 3052
33e21153 3053 if (isset($user)) {
3054 $canreply = has_capability('mod/forum:replypost', $context, $user->id, false)
a4ea3ef3 3055 && !has_capability('moodle/legacy:guest', $context, $user->id, false);
70c476a7 3056 } else {
33e21153 3057 $canreply = has_capability('mod/forum:replypost', $context, NULL, false)
a4ea3ef3 3058 && !has_capability('moodle/legacy:guest', $context, NULL, false);
70c476a7 3059 }
bbbf2d40 3060
3061 return $canreply;
70c476a7 3062}
501cdbd8 3063
bbbf2d40 3064
073286f0 3065//checks to see if a user can view a particular post
ff1dc046 3066function forum_user_can_view_post($post, $course, $cm, $forum, $discussion, $user=NULL){
073286f0 3067
3068 global $CFG, $USER;
2b63df96 3069
073286f0 3070 if (!$user){
3071 $user = $USER;
3072 }
2b63df96 3073
bbbf2d40 3074 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
0468976c 3075 if (!has_capability('mod/forum:viewdiscussion', $modcontext)) {
bbbf2d40 3076 return false;
073286f0 3077 }
073286f0 3078
ff1dc046 3079/// If it's a grouped discussion, make sure the user is a member
3080 if ($discussion->groupid > 0) {
33e21153 3081 if ($cm->groupmode == SEPARATEGROUPS) {
3082 return ismember($discussion->groupid) ||
3083 has_capability('moodle/site:accessallgroups', $modcontext);
ff1dc046 3084 }
073286f0 3085 }
ff1dc046 3086 return true;
073286f0 3087}
501cdbd8 3088
bbbf2d40 3089
951e1073 3090function forum_user_can_see_discussion($forum, $discussion, $context, $user=NULL) {
098d27d4 3091 global $USER;
3092
3093 if (empty($user) || empty($user->id)) {
3094 $user = $USER;
3095 }
3096
669f2499 3097 // retrieve objects (yuk)
098d27d4 3098 if (is_numeric($forum)) {
3099 if (!$forum = get_record('forum','id',$forum)) {
3100 return false;
3101 }
3102 }
3103 if (is_numeric($discussion)) {
3104 if (!$discussion = get_record('forum_discussions','id',$discussion)) {
3105 return false;
3106 }
3107 }
2b63df96 3108
951e1073 3109 if (!has_capability('mod/forum:viewdiscussion', $context)) {
bbbf2d40 3110 return false;
3111 }
2b63df96 3112
bbbf2d40 3113 if ($forum->type == 'qanda' &&
3114 !forum_user_has_posted($forum->id, $discussion->id, $user->id) &&
951e1073 3115 !has_capability('mod/forum:viewqandawithoutposting', $context)) {
bbbf2d40 3116 return false;
098d27d4 3117 }
3118 return true;
3119}
2b63df96 3120
098d27d4 3121
bbbf2d40 3122function forum_user_can_see_post($forum, $discussion, $post, $user=NULL) {
098d27d4 3123 global $USER;
3124
669f2499