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