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