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