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