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