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