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