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