MDL-12627 - when visiting the gradebook for the first time, we don't sort
[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 */
fffa8b35 1783function forum_get_discussions($cm, $forumsort="d.timemodified DESC", $fullpost=true, $currentgroup=-1, $limit=0, $userlastmodified=false) {
fbc21e82 1784 global $CFG, $USER;
0fcac008 1785
3d284127 1786 $timelimit = '';
1787
fffa8b35 1788 $modcontext = null;
00472a22 1789
3d284127 1790 if (!empty($CFG->forum_enabletimedposts)) {
2b63df96 1791
7613e6d7 1792 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2b63df96 1793
0468976c 1794 if (!has_capability('mod/forum:viewhiddentimedposts', $modcontext)) {
3d284127 1795 $now = time();
1796 $timelimit = " AND ((d.timestart = 0 OR d.timestart <= '$now') AND (d.timeend = 0 OR d.timeend > '$now')";
1797 if (!empty($USER->id)) {
1798 $timelimit .= " OR d.userid = '$USER->id'";
1799 }
1800 $timelimit .= ')';
fbc21e82 1801 }
fbc21e82 1802 }
1f48942e 1803
9eabd190 1804 $limitfrom = 0;
1805 $limitnum = 0;
90ec387a 1806 if ($limit) {
9eabd190 1807 $limitnum = $limit;
90ec387a 1808 }
8f0cd6ef 1809
fffa8b35 1810 $groupmode = groups_get_activity_groupmode($cm);
353228d8 1811 if ($currentgroup == -1) {
fffa8b35 1812 $currentgroup = groups_get_activity_group($cm);
353228d8 1813 }
1814
fffa8b35 1815 if ($groupmode) {
1816 if (empty($modcontext)) {
1817 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
1818 }
1819
1820 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) {
1821 if ($currentgroup) {
1822 $groupselect = "AND (d.groupid = '$currentgroup' OR d.groupid = -1)";
1823 } else {
1824 $groupselect = "";
1825 }
1826
1827 } else {
1828 //seprate groups without access all
1829 if ($currentgroup) {
1830 $groupselect = "AND (d.groupid = '$currentgroup' OR d.groupid = -1)";
1831 } else {
1832 $groupselect = "AND d.groupid = -1";
1833 }
1834 }
353228d8 1835 } else {
02509fe6 1836 $groupselect = "";
1837 }
2862b309 1838
fffa8b35 1839
29507631 1840 if (empty($forumsort)) {
1841 $forumsort = "d.timemodified DESC";
1842 }
2ab968e9 1843 if (empty($fullpost)) {
b879effb 1844 $postdata = "p.id,p.subject,p.modified,p.discussion,p.userid";
2ab968e9 1845 } else {
1846 $postdata = "p.*";
1847 }
9197e147 1848
13597d01 1849 if (empty($userlastmodified)) { // We don't need to know this
fffa8b35 1850 $umfields = "";
1851 $umtable = "";
13597d01 1852 } else {
fffa8b35 1853 $umfields = ", um.firstname AS umfirstname, um.lastname AS umlastname";
1854 $umtable = " LEFT JOIN {$CFG->prefix}user um on (d.usermodified = um.id)";
13597d01 1855 }
1856
fffa8b35 1857 return get_records_sql("SELECT $postdata, d.name, d.timemodified, d.usermodified, d.groupid,
2c894bb9 1858 u.firstname, u.lastname, u.email, u.picture, u.imagealt $umfields
93d58b30 1859 FROM {$CFG->prefix}forum_discussions d
fffa8b35 1860 JOIN {$CFG->prefix}forum_posts p ON p.discussion = d.id
1861 JOIN {$CFG->prefix}user u ON p.userid = u.id
13597d01 1862 $umtable
fffa8b35 1863 WHERE d.forum = {$cm->instance} AND p.parent = 0
1864 $timelimit $groupselect
9eabd190 1865 ORDER BY $forumsort", $limitfrom, $limitnum);
1f48942e 1866}
1867
1868
1869
0a4ac01b 1870/**
1871 * Get all discussions started by a particular user in a course (or group)
1872 * This function no longer used ...
1873 */
b656e2a9 1874function forum_get_user_discussions($courseid, $userid, $groupid=0) {
1f48942e 1875 global $CFG;
1876
b656e2a9 1877 if ($groupid) {
1878 $groupselect = " AND d.groupid = '$groupid' ";
1879 } else {
1880 $groupselect = "";
1881 }
1882
9f2ded76 1883 return get_records_sql("SELECT p.*, d.groupid, u.firstname, u.lastname, u.email, u.picture, u.imagealt,
ebc3bd2b 1884 f.type as forumtype, f.name as forumname, f.id as forumid
65b0e537 1885 FROM {$CFG->prefix}forum_discussions d,
1886 {$CFG->prefix}forum_posts p,
1887 {$CFG->prefix}user u,
1f48942e 1888 {$CFG->prefix}forum f
65b0e537 1889 WHERE d.course = '$courseid'
1890 AND p.discussion = d.id
1891 AND p.parent = 0
1892 AND p.userid = u.id
1893 AND u.id = '$userid'
b656e2a9 1894 AND d.forum = f.id $groupselect
b8bf90c5 1895 ORDER BY p.created DESC");
1f48942e 1896}
1897
0a4ac01b 1898/**
1899 * Returns list of user objects that are subscribed to this forum
1900 */
669f2499 1901function forum_subscribed_users($course, $forum, $groupid=0, $cache=false) {
0a4ac01b 1902
1f48942e 1903 global $CFG;
1904
669f2499 1905 static $resultscache = array();
1906
1907 if ($cache && isset($resultscache[$forum->id][$groupid])) {
1908 return $resultscache[$forum->id][$groupid];
1909 }
1910
6673d7bd 1911 if ($groupid) {
1d684195 1912 $grouptables = ", {$CFG->prefix}groups_members gm ";
1913 $groupselect = "AND gm.groupid = '$groupid' AND u.id = gm.userid";
1914
6673d7bd 1915 } else {
669f2499 1916 $grouptables = '';
1917 $groupselect = '';
6673d7bd 1918 }
1919
a9900c73 1920 if (forum_is_forcesubscribed($forum)) {
c37fdcb5 1921 $context = get_context_instance(CONTEXT_COURSE, $course->id);
1922 $sort = "u.email ASC";
1923 $fields ="u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat, u.maildigest, u.emailstop, u.imagealt,
1924 u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.timezone, u.theme, u.lang, u.trackforums, u.mnethostid";
1925 $results = get_users_by_capability($context, 'mod/forum:initialsubscriptions', $fields, $sort, '','','','', false, true);
669f2499 1926 } else {
9f2ded76 1927 $results = get_records_sql("SELECT u.id, u.username, u.firstname, u.lastname, u.maildisplay, u.mailformat, u.maildigest, u.emailstop, u.imagealt,
9b8ba7cd 1928 u.email, u.city, u.country, u.lastaccess, u.lastlogin, u.picture, u.timezone, u.theme, u.lang, u.trackforums, u.mnethostid
65b0e537 1929 FROM {$CFG->prefix}user u,
6673d7bd 1930 {$CFG->prefix}forum_subscriptions s $grouptables
1f48942e 1931 WHERE s.forum = '$forum->id'
65b0e537 1932 AND s.userid = u.id
6673d7bd 1933 AND u.deleted <> 1 $groupselect
7c81b6e2 1934 ORDER BY u.email ASC");
669f2499 1935 }
a044c05d 1936 // Guest user should never be subscribed to a forum.
1937 if ($guest = guest_user()) {
1938 unset($results[$guest->id]);
1939 }
669f2499 1940
1941 if ($cache) {
1942 $resultscache[$forum->id][$groupid] = $results;
1943 }
1944
1945 return $results;
1f48942e 1946}
9fa49e22 1947
067675c0 1948
1949
0a4ac01b 1950// OTHER FUNCTIONS ///////////////////////////////////////////////////////////
f93f848a 1951
1952
11b0c469 1953function forum_get_course_forum($courseid, $type) {
1954// How to set up special 1-per-course forums
a6fcdf98 1955 global $CFG;
1956
29cbd93a 1957 if ($forums = get_records_select("forum", "course = '$courseid' AND type = '$type'", "id ASC")) {
65b0e537 1958 // There should always only be ONE, but with the right combination of
29cbd93a 1959 // errors there might be more. In this case, just return the oldest one (lowest ID).
1960 foreach ($forums as $forum) {
1961 return $forum; // ie the first one
11b0c469 1962 }
8daaf761 1963 }
e6874d9f 1964
8daaf761 1965 // Doesn't exist, so create one now.
1966 $forum->course = $courseid;
1967 $forum->type = "$type";
1968 switch ($forum->type) {
1969 case "news":
65a3ef30 1970 $forum->name = addslashes(get_string("namenews", "forum"));
1971 $forum->intro = addslashes(get_string("intronews", "forum"));
906fef94 1972 $forum->forcesubscribe = FORUM_FORCESUBSCRIBE;
8daaf761 1973 $forum->assessed = 0;
709f0ec8 1974 if ($courseid == SITEID) {
1975 $forum->name = get_string("sitenews");
1976 $forum->forcesubscribe = 0;
8f0cd6ef 1977 }
8daaf761 1978 break;
1979 case "social":
65a3ef30 1980 $forum->name = addslashes(get_string("namesocial", "forum"));
1981 $forum->intro = addslashes(get_string("introsocial", "forum"));
8daaf761 1982 $forum->assessed = 0;
1983 $forum->forcesubscribe = 0;
1984 break;
8daaf761 1985 default:
1986 notify("That forum type doesn't exist!");
1987 return false;
1988 break;
1989 }
1990
1991 $forum->timemodified = time();
1992 $forum->id = insert_record("forum", $forum);
1993
e1b5643f 1994 if (! $module = get_record("modules", "name", "forum")) {
1995 notify("Could not find forum module!!");
1996 return false;
82aa0e8d 1997 }
0b5a80a1 1998 $mod = new object();
e1b5643f 1999 $mod->course = $courseid;
2000 $mod->module = $module->id;
2001 $mod->instance = $forum->id;
2002 $mod->section = 0;
2003 if (! $mod->coursemodule = add_course_module($mod) ) { // assumes course/lib.php is loaded
1306c5ea 2004 notify("Could not add a new course module to the course '" . format_string($course->fullname) . "'");
e1b5643f 2005 return false;
2006 }
2007 if (! $sectionid = add_mod_to_section($mod) ) { // assumes course/lib.php is loaded
2008 notify("Could not add the new course module to that section");
2009 return false;
2010 }
2011 if (! set_field("course_modules", "section", $sectionid, "id", $mod->coursemodule)) {
2012 notify("Could not update the course module with the correct section");
2013 return false;
2014 }
2015 include_once("$CFG->dirroot/course/lib.php");
2016 rebuild_course_cache($courseid);
65b0e537 2017
8daaf761 2018 return get_record("forum", "id", "$forum->id");
82aa0e8d 2019}
2020
f93f848a 2021
0a4ac01b 2022/**
2023* Given the data about a posting, builds up the HTML to display it and
2024* returns the HTML in a string. This is designed for sending via HTML email.
2025*/
65b0e537 2026function forum_make_mail_post(&$post, $user, $touser, $course,
11b0c469 2027 $ownpost=false, $reply=false, $link=false, $rate=false, $footer="") {
2b63df96 2028
501cdbd8 2029
15f81ee3 2030 global $CFG, $USER;
501cdbd8 2031
1306c5ea 2032 // the old caching was removed for now, because it did not work due to recent changes in cron
0d851f90 2033
ee8e0008 2034 $post->forum = get_field('forum_discussions', 'forum', 'id', $post->discussion);
2b63df96 2035
ee8e0008 2036 if (!$cm = get_coursemodule_from_instance('forum', $post->forum)) {
2a692058 2037 mtrace('Course Module ID was incorrect');
7613e6d7 2038 }
2039 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
2040
1306c5ea 2041 // format the post body
2042 $options = new object();
2043 $options->para = true;
2044 $formattedtext = format_text(trusttext_strip($post->message), $post->format, $options, $course->id);
0d851f90 2045
add3201e 2046 $output = '<table border="0" cellpadding="3" cellspacing="0" class="forumpost">';
501cdbd8 2047
add3201e 2048 $output .= '<tr class="header"><td width="35" valign="top" class="picture left">';
501cdbd8 2049 $output .= print_user_picture($user->id, $course->id, $user->picture, false, true);
add3201e 2050 $output .= '</td>';
501cdbd8 2051
2052 if ($post->parent) {
add3201e 2053 $output .= '<td class="topic">';
501cdbd8 2054 } else {
add3201e 2055 $output .= '<td class="topic starter">';
501cdbd8 2056 }
add3201e 2057 $output .= '<div class="subject">'.format_string($post->subject).'</div>';
1b26d5e7 2058
15f81ee3 2059 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $modcontext));
1306c5ea 2060 $by = new object();
add3201e 2061 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
2062 $by->date = userdate($post->modified, '', $touser->timezone);
2063 $output .= '<div class="author">'.get_string('bynameondate', 'forum', $by).'</div>';
2064
2065 $output .= '</td></tr>';
2066
7b54f563 2067 $output .= '<tr><td class="left side" valign="top">';
2c386f82 2068 if ($group = groups_get_all_groups($course->id, $user->id)) {
f393f545 2069 $output .= print_group_picture($group, $course->id, false, true, true);
add3201e 2070 } else {
2071 $output .= '&nbsp;';
2072 }
1b26d5e7 2073
add3201e 2074 $output .= '</td><td class="content">';
501cdbd8 2075
7f6689e4 2076 if ($post->attachment) {
2077 $post->course = $course->id;
add3201e 2078 $output .= '<div class="attachments">';
2079 $output .= forum_print_attachments($post, 'html');
72d497d4 2080 $output .= "</div>";
7f6689e4 2081 }
2082
0d851f90 2083 $output .= $formattedtext;
501cdbd8 2084
0a4ac01b 2085// Commands
add3201e 2086 $commands = array();
501cdbd8 2087
2e2e71a8 2088 if ($post->parent) {
add3201e 2089 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2090 $post->discussion.'&amp;parent='.$post->parent.'">'.get_string('parent', 'forum').'</a>';
2e2e71a8 2091 }
ce45515e 2092
add3201e 2093 if ($reply) {
2094 $commands[] = '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.
2095 get_string('reply', 'forum').'</a>';
501cdbd8 2096 }
2097
add3201e 2098 $output .= '<div class="commands">';
2099 $output .= implode(' | ', $commands);
2100 $output .= '</div>';
2101
0a4ac01b 2102// Context link to post if required
501cdbd8 2103 if ($link) {
add3201e 2104 $output .= '<div class="link">';
0be4d8bf 2105 $output .= '<a target="_blank" href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#p'.$post->id.'">'.
2b63df96 2106 get_string('postincontext', 'forum').'</a>';
add3201e 2107 $output .= '</div>';
501cdbd8 2108 }
add3201e 2109
501cdbd8 2110 if ($footer) {
add3201e 2111 $output .= '<div class="footer">'.$footer.'</div>';
501cdbd8 2112 }
add3201e 2113 $output .= '</td></tr></table>'."\n\n";
2114
501cdbd8 2115 return $output;
2116}
2117
0a4ac01b 2118/**
21976af1 2119 * Print a forum post
2120 *
2121 * @param object $post The post to print.
2122 * @param integer $courseid The course this post belongs to.
2123 * @param boolean $ownpost Whether this post belongs to the current user.
2124 * @param boolean $reply Whether to print a 'reply' link at the bottom of the message.
2125 * @param boolean $link Just print a shortened version of the post as a link to the full post.
2126 * @param object $ratings -- I don't really know --
2127 * @param string $footer Extra stuff to print after the message.
2128 * @param string $highlight Space-separated list of terms to highlight.
2129 * @param int $post_read true, false or -99. If we already know whether this user
2130 * has read this post, pass that in, otherwise, pass in -99, and this
2131 * function will work it out.
2132 * @param boolean $dummyifcantsee When forum_user_can_see_post says that
2133 * the current user can't see this post, if this argument is true
2134 * (the default) then print a dummy 'you can't see this post' post.
2135 * If false, don't output anything at all.
0a4ac01b 2136 */
65b0e537 2137function forum_print_post(&$post, $courseid, $ownpost=false, $reply=false, $link=false,
21976af1 2138 $ratings=NULL, $footer="", $highlight="", $post_read=-99, $dummyifcantsee=true) {
74f5d1e3 2139
21976af1 2140 global $USER, $CFG;
501cdbd8 2141
951e1073 2142 static $stredit, $strdelete, $strreply, $strparent, $strprune;
5d82704e 2143 static $strpruneheading, $displaymode;
77efef3e 2144 static $strmarkread, $strmarkunread, $istracked;
f37da850 2145
951e1073 2146
c15b86dc 2147 if (empty($post->modcontext)) { // Have to generate it, which is expensive! Should always be set.
2148 if (empty($post->forum)) {
2149 $discussion = get_record('forum_discussions', 'id', $post->discussion);
2150 $post->forum = $discussion->forum;
2151 }
2152 if (!$cm = get_coursemodule_from_instance('forum', $post->forum)) {
2153 error('Course Module ID was incorrect');
2154 }
2155 $post->modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
951e1073 2156 }
951e1073 2157
098d27d4 2158 if (!forum_user_can_see_post($post->forum,$post->discussion,$post)) {
21976af1 2159 if (!$dummyifcantsee) {
098d27d4 2160 return;
2b63df96 2161 }
0be4d8bf 2162 echo '<a id="p'.$post->id.'"></a>';
098d27d4 2163 echo '<table cellspacing="0" class="forumpost">';
2164 echo '<tr class="header"><td class="picture left">';
2165 // print_user_picture($post->userid, $courseid, $post->picture);
2166 echo '</td>';
2167 if ($post->parent) {
2168 echo '<td class="topic">';
2169 } else {
2170 echo '<td class="topic starter">';
2171 }
2172 echo '<div class="subject">'.get_string('forumsubjecthidden','forum').'</div>';
2173 echo '<div class="author">';
2174 print_string('forumauthorhidden','forum');
2175 echo '</div></td></tr>';
2b63df96 2176
098d27d4 2177 echo '<tr><td class="left side">';
2178 echo '&nbsp;';
2b63df96 2179
0a4ac01b 2180 // Actual content
2b63df96 2181
098d27d4 2182 echo '</td><td class="content">'."\n";
2183 echo get_string('forumbodyhidden','forum');
2184 echo '</td></tr></table>';
2185 return;
2186 }
2187
2e2e71a8 2188 if (empty($stredit)) {
359f2758 2189 $stredit = get_string('edit', 'forum');
2190 $strdelete = get_string('delete', 'forum');
2191 $strreply = get_string('reply', 'forum');
2192 $strparent = get_string('parent', 'forum');
2193 $strpruneheading = get_string('pruneheading', 'forum');
d494dd83 2194 $strprune = get_string('prune', 'forum');
5d82704e 2195 $displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode);
f37da850 2196 $strmarkread = get_string('markread', 'forum');
2197 $strmarkunread = get_string('markunread', 'forum');
77efef3e 2198
2199 if (!empty($post->forum)) {
2b63df96 2200 $istracked = (forum_tp_can_track_forums($post->forum) &&
77efef3e 2201 forum_tp_is_tracked($post->forum));
2202 } else {
2203 $istracked = false;
2204 }
f37da850 2205 }
2206
eaf50aef 2207 if ($istracked) {
f37da850 2208 if ($post_read == -99) { // If we don't know yet...
0a4ac01b 2209 // The front page can display a news item post to non-logged in users. This should
2210 // always appear as 'read'.
489de4ae 2211 $post_read = empty($USER) || forum_tp_is_post_read($USER->id, $post);
f37da850 2212 }
2213 if ($post_read) {
2214 $read_style = ' read';
2215 } else {
2216 $read_style = ' unread';
2217 echo '<a name="unread"></a>';
2218 }
2219 } else {
2220 $read_style = '';
2e2e71a8 2221 }
2222
0be4d8bf 2223 echo '<a id="p'.$post->id.'"></a>';
33200577 2224 echo '<table cellspacing="0" class="forumpost'.$read_style.'">';
501cdbd8 2225
21064440 2226 // Picture
2227 $postuser = new object;
2228 $postuser->id = $post->userid;
2229 $postuser->firstname = $post->firstname;
2230 $postuser->lastname = $post->lastname;
2231 $postuser->imagealt = $post->imagealt;
2232 $postuser->picture = $post->picture;
2233
d3583b41 2234 echo '<tr class="header"><td class="picture left">';
21064440 2235 print_user_picture($postuser, $courseid);
d3583b41 2236 echo '</td>';
501cdbd8 2237
2238 if ($post->parent) {
d3583b41 2239 echo '<td class="topic">';
501cdbd8 2240 } else {
d3583b41 2241 echo '<td class="topic starter">';
501cdbd8 2242 }
83ec9098 2243
5b1059bb 2244 if (!empty($post->subjectnoformat)) {
2245 echo '<div class="subject">'.$post->subject.'</div>';
acc7a2fa 2246 } else {
2247 echo '<div class="subject">'.format_string($post->subject).'</div>';
2248 }
e3ff14ca 2249
d3583b41 2250 echo '<div class="author">';
c15b86dc 2251 $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $post->modcontext));
0b5a80a1 2252 $by = new object();
d3583b41 2253 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
2254 $post->userid.'&amp;course='.$courseid.'">'.$fullname.'</a>';
d62413e8 2255 $by->date = userdate($post->modified);
d3583b41 2256 print_string('bynameondate', 'forum', $by);
2257 echo '</div></td></tr>';
1b26d5e7 2258
d3583b41 2259 echo '<tr><td class="left side">';
2c386f82 2260 if ($group = groups_get_all_groups($courseid, $post->userid)) {
a4fbb0b2 2261 print_group_picture($group, $courseid, false, false, true);
507407a7 2262 } else {
d3583b41 2263 echo '&nbsp;';
507407a7 2264 }
d3583b41 2265
0a4ac01b 2266// Actual content
d3583b41 2267
2268 echo '</td><td class="content">'."\n";
501cdbd8 2269
7f6689e4 2270 if ($post->attachment) {
2271 $post->course = $courseid;
d3583b41 2272 $post->forum = get_field('forum_discussions', 'forum', 'id', $post->discussion);
2273 echo '<div class="attachments">';
72d497d4 2274 $attachedimages = forum_print_attachments($post);
d3583b41 2275 echo '</div>';
e9c2dc1f 2276 } else {
d3583b41 2277 $attachedimages = '';
7f6689e4 2278 }
2279
d3583b41 2280
326ce3c4 2281 $options = new Object;
2282 $options->para = false;
f2b5d7e3 2283 $options->trusttext = true;
5be7800c 2284 if ($link and (strlen(strip_tags($post->message)) > $CFG->forum_longpost)) {
aa153f29 2285 // Print shortened version
326ce3c4 2286 echo format_text(forum_shorten_post($post->message), $post->format, $options, $courseid);
c585fa17 2287 $numwords = count_words(strip_tags($post->message));
d3583b41 2288 echo '<p><a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
2289 echo get_string('readtherest', 'forum');
2290 echo '</a> ('.get_string('numwords', '', $numwords).')...</p>';
501cdbd8 2291 } else {
aa153f29 2292 // Print whole message
88438a58 2293 if ($highlight) {
326ce3c4 2294 echo highlight($highlight, format_text($post->message, $post->format, $options, $courseid));
88438a58 2295 } else {
326ce3c4 2296 echo format_text($post->message, $post->format, $options, $courseid);
88438a58 2297 }
65b0e537 2298 echo $attachedimages;
501cdbd8 2299 }
2300
d3583b41 2301
0a4ac01b 2302// Commands
d3583b41 2303
359f2758 2304 $commands = array();
501cdbd8 2305
eaf50aef 2306 if ($istracked) {
0a4ac01b 2307 // SPECIAL CASE: The front page can display a news item post to non-logged in users.
2308 // Don't display the mark read / unread controls in this case.
489de4ae 2309 if ($CFG->forum_usermarksread && !empty($USER)) {
f37da850 2310 if ($post_read) {
2311 $mcmd = '&amp;mark=unread&amp;postid='.$post->id;
2312 $mtxt = $strmarkunread;
2313 } else {
2314 $mcmd = '&amp;mark=read&amp;postid='.$post->id;
2315 $mtxt = $strmarkread;
2316 }
5d82704e 2317 if ($displaymode == FORUM_MODE_THREADED) {
d3583b41 2318 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2319 $post->discussion.'&amp;parent='.$post->id.$mcmd.'">'.$mtxt.'</a>';
f37da850 2320 } else {
d3583b41 2321 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
0be4d8bf 2322 $post->discussion.$mcmd.'#p'.$post->id.'">'.$mtxt.'</a>';
f37da850 2323 }
2324 }
2325 }
2326
2db01bec 2327 if ($post->parent) { // Zoom in to the parent specifically
5d82704e 2328 if ($displaymode == FORUM_MODE_THREADED) {
2329 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2db01bec 2330 $post->discussion.'&amp;parent='.$post->parent.'">'.$strparent.'</a>';
5d82704e 2331 } else {
2332 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.
2333 $post->discussion.'#p'.$post->parent.'">'.$strparent.'</a>';
2334 }
2e2e71a8 2335 }
2336
c15b86dc 2337 if (!isset($post->forumtype)) {
2338 $post->forumtype = get_field('forum', 'type', 'id', $post->forum);
2339 }
2b63df96 2340
501cdbd8 2341 $age = time() - $post->created;
0a4ac01b 2342 // Hack for allow to edit news posts those are not displayed yet until they are displayed
fbc21e82 2343 if (!$post->parent
c15b86dc 2344 && $post->forumtype == 'news'
fbc21e82 2345 && get_field_sql("SELECT id FROM {$CFG->prefix}forum_discussions WHERE id = $post->discussion AND timestart > ".time())) {
2346 $age = 0;
2347 }
c15b86dc 2348 $editanypost = has_capability('mod/forum:editanypost', $post->modcontext);
6e372b25 2349
a4ea3ef3 2350 if ($ownpost or $editanypost) {
951e1073 2351 if (($age < $CFG->maxeditingtime) or $editanypost) {
d3583b41 2352 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?edit='.$post->id.'">'.$stredit.'</a>';
501cdbd8 2353 }
64eacd6f 2354 }
aaf7a9dc 2355
c15b86dc 2356 if (has_capability('mod/forum:splitdiscussions', $post->modcontext)
2357 && $post->parent && $post->forumtype != 'single') {
66035aaf 2358
d3583b41 2359 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?prune='.$post->id.
2360 '" title="'.$strpruneheading.'">'.$strprune.'</a>';
cf84431b 2361 }
aaf7a9dc 2362
9fbccd39 2363 if (($ownpost and $age < $CFG->maxeditingtime
c15b86dc 2364 and has_capability('mod/forum:deleteownpost', $post->modcontext))
2365 or has_capability('mod/forum:deleteanypost', $post->modcontext)) {
d3583b41 2366 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?delete='.$post->id.'">'.$strdelete.'</a>';
64eacd6f 2367 }
359f2758 2368
a4ea3ef3 2369 if ($reply) {
d3583b41 2370 $commands[] = '<a href="'.$CFG->wwwroot.'/mod/forum/post.php?reply='.$post->id.'">'.$strreply.'</a>';
501cdbd8 2371 }
501cdbd8 2372
d3583b41 2373 echo '<div class="commands">';
2374 echo implode(' | ', $commands);
2375 echo '</div>';
2376
2377
0a4ac01b 2378// Ratings
74f5d1e3 2379
2380 $ratingsmenuused = false;
02ebf404 2381 if (!empty($ratings) and !empty($USER->id)) {
d3583b41 2382 echo '<div class="ratings">';
98914efd 2383 $useratings = true;
2384 if ($ratings->assesstimestart and $ratings->assesstimefinish) {
2385 if ($post->created < $ratings->assesstimestart or $post->created > $ratings->assesstimefinish) {
2386 $useratings = false;
2387 }
2388 }
2389 if ($useratings) {
3bd98ad4 2390 $mypost = ($USER->id == $post->userid);
2b63df96 2391
c15b86dc 2392 $canviewallratings = has_capability('mod/forum:viewanyrating', $post->modcontext);
2b63df96 2393
2394 if ($canviewallratings and !$mypost) {
951e1073 2395 forum_print_ratings_mean($post->id, $ratings->scale, $canviewallratings);
d395046a 2396 if (!empty($ratings->allow)) {
d3583b41 2397 echo '&nbsp;';
d395046a 2398 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
2399 $ratingsmenuused = true;
2400 }
3bd98ad4 2401
2402 } else if ($mypost) {
2403 forum_print_ratings_mean($post->id, $ratings->scale, true);
2404
98914efd 2405 } else if (!empty($ratings->allow) ) {
2406 forum_print_rating_menu($post->id, $USER->id, $ratings->scale);
74f5d1e3 2407 $ratingsmenuused = true;
2a3cda19 2408 }
501cdbd8 2409 }
d3583b41 2410 echo '</div>';
501cdbd8 2411 }
65b0e537 2412
0a4ac01b 2413// Link to post if required
d3583b41 2414
501cdbd8 2415 if ($link) {
d3583b41 2416 echo '<div class="link">';
501cdbd8 2417 if ($post->replies == 1) {
d3583b41 2418 $replystring = get_string('repliesone', 'forum', $post->replies);
501cdbd8 2419 } else {
d3583b41 2420 $replystring = get_string('repliesmany', 'forum', $post->replies);
501cdbd8 2421 }
d3583b41 2422 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">'.
2423 get_string('discussthistopic', 'forum').'</a>&nbsp;('.$replystring.')';
2424 echo '</div>';
501cdbd8 2425 }
d3583b41 2426
501cdbd8 2427 if ($footer) {
d3583b41 2428 echo '<div class="footer">'.$footer.'</div>';
501cdbd8 2429 }
d3583b41 2430 echo '</td></tr></table>'."\n\n";
74f5d1e3 2431
eaf50aef 2432 if ($istracked && !$CFG->forum_usermarksread && !empty($post->forum)) {
f37da850 2433 forum_tp_mark_post_read($USER->id, $post, $post->forum);
2434 }
2435
74f5d1e3 2436 return $ratingsmenuused;
501cdbd8 2437}
42fb3c85 2438
2439
eaf50aef 2440/**
0a4ac01b 2441 * This function prints the overview of a discussion in the forum listing.
2442 * It needs some discussion information and some post information, these
2443 * happen to be combined for efficiency in the $post parameter by the function
2444 * that calls this one: forum_print_latest_discussions()
2445 *
2446 * @param object $post The post object (passed by reference for speed).
2447 * @param object $forum The forum object.
2448 * @param int $group Current group.
2449 * @param string $datestring Format to use for the dates.
2450 * @param boolean $cantrack Is tracking enabled for this forum.
2451 * @param boolean $forumtracked Is the user tracking this forum.
2452 * @param boolean $canviewparticipants True if user has the viewparticipants permission for this course
2453 */
951e1073 2454function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring="",
2c894bb9 2455 $cantrack=true, $forumtracked=true, $canviewparticipants=true, $modcontext=NULL) {
43921b8a 2456
d30867b0 2457 global $USER, $CFG;
3335f6fb 2458
f51e8d7e 2459 static $rowcount;
5733262d 2460 static $strmarkalldread;
f51e8d7e 2461
2c894bb9 2462 if (empty($modcontext)) {
2463 if (!$cm = get_coursemodule_from_instance('forum', $forum->id, $forum->course)) {
2464 error('Course Module ID was incorrect');
2465 }
2466 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
951e1073 2467 }
951e1073 2468
f51e8d7e 2469 if (!isset($rowcount)) {
2470 $rowcount = 0;
5733262d 2471 $strmarkalldread = get_string('markalldread', 'forum');
f51e8d7e 2472 } else {
2473 $rowcount = ($rowcount + 1) % 2;
2474 }
2475
17dc3f3c 2476 $post->subject = format_string($post->subject,true);
436a7cae 2477
f51e8d7e 2478 echo "\n\n";
2479 echo '<tr class="discussion r'.$rowcount.'">';
3335f6fb 2480
29507631 2481 // Topic
f51e8d7e 2482 echo '<td class="topic starter">';
2483 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">'.$post->subject.'</a>';
29507631 2484 echo "</td>\n";
2485
2486 // Picture
2c894bb9 2487 $postuser = new object;
2488 $postuser->id = $post->userid;
2489 $postuser->firstname = $post->firstname;
2490 $postuser->lastname = $post->lastname;
2491 $postuser->imagealt = $post->imagealt;
2492 $postuser->picture = $post->picture;
2493
f51e8d7e 2494 echo '<td class="picture">';
2c894bb9 2495 print_user_picture($postuser, $forum->course);
29507631 2496 echo "</td>\n";
3335f6fb 2497
29507631 2498 // User name
951e1073 2499 $fullname = fullname($post, has_capability('moodle/site:viewfullnames', $modcontext));
f51e8d7e 2500 echo '<td class="author">';
2501 echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->userid.'&amp;course='.$forum->course.'">'.$fullname.'</a>';
29507631 2502 echo "</td>\n";
2503
3a68fbbb 2504 // Group picture
425b4f1a 2505 if ($group !== -1) { // Groups are active - group is a group data object or NULL
f51e8d7e 2506 echo '<td class="picture group">';
c2b552fe 2507 if (!empty($group->picture) and empty($group->hidepicture)) {
3a68fbbb 2508 print_group_picture($group, $forum->course, false, false, true);
2509 } else if (isset($group->id)) {
18d6ef01 2510 if($canviewparticipants) {
2511 echo '<a href="'.$CFG->wwwroot.'/user/index.php?id='.$forum->course.'&amp;group='.$group->id.'">'.$group->name.'</a>';
2512 } else {
2513 echo $group->name;
2514 }
3a68fbbb 2515 }
2516 echo "</td>\n";
2517 }
2518
f0da6b85 2519 if (has_capability('mod/forum:viewdiscussion', $modcontext)) { // Show the column with replies
f51e8d7e 2520 echo '<td class="replies">';
2521 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'">';
2522 echo $post->replies.'</a>';
a796d0b8 2523 echo "</td>\n";
e3ff14ca 2524
eaf50aef 2525 if ($cantrack) {
f51e8d7e 2526 echo '<td class="replies">';
eaf50aef 2527 if ($forumtracked) {
2528 if ($post->unread > 0) {
2529 echo '<span class="unread">';
2530 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.'#unread">';
2531 echo $post->unread;
2532 echo '</a>';
c39748f4 2533 echo '<a title="'.$strmarkalldread.'" href="'.$CFG->wwwroot.'/mod/forum/markposts.php?f='.
eaf50aef 2534 $forum->id.'&amp;d='.$post->discussion.'&amp;mark=read&amp;returnpage=view.php">' .
0d905d9f 2535 '<img src="'.$CFG->pixpath.'/t/clear.gif" class="iconsmall" alt="'.$strmarkalldread.'" /></a>';
eaf50aef 2536 echo '</span>';
2537 } else {
2538 echo '<span class="read">';
eaf50aef 2539 echo $post->unread;
eaf50aef 2540 echo '</span>';
2541 }
f51e8d7e 2542 } else {
343af274 2543 echo '<span class="read">';
eaf50aef 2544 echo '-';
343af274 2545 echo '</span>';
3a68fbbb 2546 }
f37da850 2547 echo "</td>\n";
2548 }
a796d0b8 2549 }
3335f6fb 2550
f51e8d7e 2551 echo '<td class="lastpost">';
43921b8a 2552 $usedate = (empty($post->timemodified)) ? $post->modified : $post->timemodified; // Just in case
839f2456 2553 $parenturl = (empty($post->lastpostid)) ? '' : '&amp;parent='.$post->lastpostid;
0b5a80a1 2554 $usermodified = new object();
098d27d4 2555 $usermodified->id = $post->usermodified;
268c6485 2556 $usermodified->firstname = $post->umfirstname;
2557 $usermodified->lastname = $post->umlastname;
f51e8d7e 2558 echo '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$post->usermodified.'&amp;course='.$forum->course.'">'.
2559 fullname($usermodified).'</a><br />';
ac00b904 2560 echo '<a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$post->discussion.$parenturl.'">'.
43921b8a 2561 userdate($usedate, $datestring).'</a>';
29507631 2562 echo "</td>\n";
2563
f51e8d7e 2564 echo "</tr>\n\n";
3335f6fb 2565
3335f6fb 2566}
2567
2568
0a4ac01b 2569/**
2570 * Given a post object that we already know has a long message
2571 * this function truncates the message nicely to the first
2572 * sane place between $CFG->forum_longpost and $CFG->forum_shortpost
2573 */
aa153f29 2574function forum_shorten_post($message) {
5be7800c 2575
2576 global $CFG;
c585fa17 2577
2578 $i = 0;
2579 $tag = false;
2580 $length = strlen($message);
2581 $count = 0;
2582 $stopzone = false;
2583 $truncate = 0;
2584
2585 for ($i=0; $i<$length; $i++) {
a8afb411 2586 $char = $message[$i];
c585fa17 2587
2588 switch ($char) {
65b0e537 2589 case "<":
c585fa17 2590 $tag = true;
2591 break;
65b0e537 2592 case ">":
c585fa17 2593 $tag = false;
2594 break;
2595 default:
2596 if (!$tag) {
2597 if ($stopzone) {
67f0b4cc 2598 if ($char == ".") {
a8afb411 2599 $truncate = $i+1;
c585fa17 2600 break 2;
2601 }
2602 }
2603 $count++;
2604 }
a8afb411 2605 break;
c585fa17 2606 }
2607 if (!$stopzone) {
5be7800c 2608 if ($count > $CFG->forum_shortpost) {
c585fa17 2609 $stopzone = true;
2610 }
2611 }
2612 }
aa153f29 2613
c585fa17 2614 if (!$truncate) {
a8afb411 2615 $truncate = $i;
c585fa17 2616 }
2617
67f0b4cc 2618 return substr($message, 0, $truncate);
aa153f29 2619}
2620
501cdbd8 2621
0a4ac01b 2622/**
2623 * Print the multiple ratings on a post given to the current user by others.
2624 * Scale is an array of ratings
2625 */
3bd98ad4 2626function forum_print_ratings_mean($postid, $scale, $link=true) {
02ebf404 2627
2628 static $strrate;
05c47ef7 2629
2630 $mean = forum_get_ratings_mean($postid, $scale);
65b0e537 2631
05c47ef7 2632 if ($mean !== "") {
02ebf404 2633
2634 if (empty($strratings)) {
2635 $strratings = get_string("ratings", "forum");
501cdbd8 2636 }
501cdbd8 2637
02ebf404 2638 echo "$strratings: ";
3bd98ad4 2639 if ($link) {
2640 link_to_popup_window ("/mod/forum/report.php?id=$postid", "ratings", $mean, 400, 600);
2641 } else {
2642 echo "$mean ";
2643 }
501cdbd8 2644 }
2645}
2646
501cdbd8 2647
0a4ac01b 2648/**
2649 * Return the mean rating of a post given to the current user by others.
2650 * Scale is an array of possible ratings in the scale
2651 * Ratings is an optional simple array of actual ratings (just integers)
2652 */
0761d83f 2653function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {
02ebf404 2654
2655 if (!$ratings) {
2656 $ratings = array();
2657 if ($rates = get_records("forum_ratings", "post", $postid)) {
2658 foreach ($rates as $rate) {
2659 $ratings[] = $rate->rating;
2660 }
501cdbd8 2661 }
501cdbd8 2662 }
02ebf404 2663
0761d83f 2664 $count = count($ratings);
2665
2666 if ($count == 0) {
02ebf404 2667 return "";
02ebf404 2668
0761d83f 2669 } else if ($count == 1) {
2670 return $scale[$ratings[0]];
2671
02ebf404 2672 } else {
0761d83f 2673 $total = 0;
2674 foreach ($ratings as $rating) {
2675 $total += $rating;
2676 }
2677 $mean = round( ((float)$total/(float)$count) + 0.001); // Little fudge factor so that 0.5 goes UP
65b0e537 2678
0761d83f 2679 if (isset($scale[$mean])) {
2680 return $scale[$mean]." ($count)";
2681 } else {
2682 return "$mean ($count)"; // Should never happen, hopefully
2683 }
02ebf404 2684 }
2685}
2686
0a4ac01b 2687/**
2688 * Return a summary of post ratings given to the current user by others.
2689 * Scale is an array of possible ratings in the scale
2690 * Ratings is an optional simple array of actual ratings (just integers)
2691 */
02ebf404 2692function forum_get_ratings_summary($postid, $scale, $ratings=NULL) {
02ebf404 2693
2694 if (!$ratings) {
2695 $ratings = array();
2696 if ($rates = get_records("forum_ratings", "post", $postid)) {
2697 foreach ($rates as $rate) {
2698 $rating[] = $rate->rating;
2699 }
2700 }
2701 }
2702
2703
2704 if (!$count = count($ratings)) {
2705 return "";
2706 }
2707
2708
2709 foreach ($scale as $key => $scaleitem) {
2710 $sumrating[$key] = 0;
2711 }
2712
2713 foreach ($ratings as $rating) {
2714 $sumrating[$rating]++;
2715 }
2716
2717 $summary = "";
2718 foreach ($scale as $key => $scaleitem) {
2719 $summary = $sumrating[$key].$summary;
2720 if ($key > 1) {
2721 $summary = "/$summary";
2722 }
2723 }
2724 return $summary;
2725}
2726
0a4ac01b 2727/**
2728 * Print the menu of ratings as part of a larger form.
2729 * If the post has already been - set that value.
2730 * Scale is an array of ratings
2731 */
02ebf404 2732function forum_print_rating_menu($postid, $userid, $scale) {
02ebf404 2733
2734 static $strrate;
2735
2736 if (!$rating = get_record("forum_ratings", "userid", $userid, "post", $postid)) {
1a7cdb11 2737 $rating->rating = FORUM_UNSET_POST_RATING;
02ebf404 2738 }
2739
2740 if (empty($strrate)) {
2741 $strrate = get_string("rate", "forum");
2742 }
1a7cdb11 2743 $scale = array(FORUM_UNSET_POST_RATING => $strrate.'...') + $scale;
2744 choose_from_menu($scale, $postid, $rating->rating, '');
501cdbd8 2745}
2746
83da3d28 2747/**
2748 * Print the drop down that allows the user to select how they want to have
2749 * the discussion displayed.
2750 * @param $id - forum id if $forumtype is 'single',
2751 * discussion id for any other forum type
2752 * @param $mode - forum layout mode
2753 * @param $forumtype - optional
2754 */
2755function forum_print_mode_form($id, $mode, $forumtype='') {
f0ef40c5 2756 global $FORUM_LAYOUT_MODES;
501cdbd8 2757
83da3d28 2758 if ($forumtype == 'single') {
2759 popup_form("view.php?f=$id&amp;mode=", $FORUM_LAYOUT_MODES, "mode", $mode, "");
2760 } else {
2761 popup_form("discuss.php?d=$id&amp;mode=", $FORUM_LAYOUT_MODES, "mode", $mode, "");
2762 }
501cdbd8 2763}
2764
0a4ac01b 2765/**
3a5e1d06 2766 *
0a4ac01b 2767 */
6f1cc8d6 2768function forum_search_form($course, $search='') {
501cdbd8 2769 global $CFG;
2770
81d22774 2771 $output = '<div class="forumsearch">';
2772 $output .= '<form action="'.$CFG->wwwroot.'/mod/forum/search.php" style="display:inline">';
d69e9c15 2773 $output .= '<fieldset class="invisiblefieldset">';
bbbf2d40 2774 $output .= helpbutton('search', get_string('search'), 'moodle', true, false, '', true);
d66dc4b2 2775 $output .= '<input name="search" type="text" size="18" value="'.s($search, true).'" alt="search" />';
6f1cc8d6 2776 $output .= '<input value="'.get_string('searchforums', 'forum').'" type="submit" />';
2777 $output .= '<input name="id" type="hidden" value="'.$course->id.'" />';
81d22774 2778 $output .= '</fieldset>';
6f1cc8d6 2779 $output .= '</form>';
81d22774 2780 $output .= '</div>';
5e367a2d 2781
6f1cc8d6 2782 return $output;
501cdbd8 2783}
2784
2785
0a4ac01b 2786/**
3a5e1d06 2787 *
0a4ac01b 2788 */
11b0c469 2789function forum_set_return() {
607809b3 2790 global $CFG, $SESSION;
501cdbd8 2791
28e1e8b9 2792 if (! isset($SESSION->fromdiscussion)) {
48d38fad 2793 if (!empty($_SERVER['HTTP_REFERER'])) {
2794 $referer = $_SERVER['HTTP_REFERER'];
2795 } else {
2796 $referer = "";
2797 }
28e1e8b9 2798 // If the referer is NOT a login screen then save it.
48d38fad 2799 if (! strncasecmp("$CFG->wwwroot/login", $referer, 300)) {
607809b3 2800 $SESSION->fromdiscussion = $_SERVER["HTTP_REFERER"];
28e1e8b9 2801 }
501cdbd8 2802 }
2803}
2804
2805
0a4ac01b 2806/**
3a5e1d06 2807 *
0a4ac01b 2808 */
11b0c469 2809function forum_go_back_to($default) {
501cdbd8 2810 global $SESSION;
2811
9c9f7d77 2812 if (!empty($SESSION->fromdiscussion)) {
501cdbd8 2813 $returnto = $SESSION->fromdiscussion;
2814 unset($SESSION->fromdiscussion);
2815 return $returnto;
2816 } else {
2817 return $default;
2818 }
2819}
2820
0a4ac01b 2821/**
2822 * Creates a directory file name, suitable for make_upload_directory()
2823 */
7f6689e4 2824function forum_file_area_name($post) {
7f6689e4 2825 global $CFG;
2826
2827 return "$post->course/$CFG->moddata/forum/$post->forum/$post->id";
2828}
2829
0a4ac01b 2830/**
3a5e1d06 2831 *
0a4ac01b 2832 */
7f6689e4 2833function forum_file_area($post) {
2834 return make_upload_directory( forum_file_area_name($post) );
2835}
2836
0a4ac01b 2837/**
3a5e1d06 2838 *
0a4ac01b 2839 */
7f6689e4 2840function forum_delete_old_attachments($post, $exception="") {
7f6689e4 2841
0a4ac01b 2842/**
2843 * Deletes all the user files in the attachments area for a post
2844 * EXCEPT for any file named $exception
2845 */
7f6689e4 2846 if ($basedir = forum_file_area($post)) {
2847 if ($files = get_directory_list($basedir)) {
2848 foreach ($files as $file) {
2849 if ($file != $exception) {
2850 unlink("$basedir/$file");
2851 notify("Existing file '$file' has been deleted!");
2852 }
2853 }
2854 }
2855 if (!$exception) { // Delete directory as well, if empty
2856 rmdir("$basedir");
2857 }
2858 }
2859}
2860
0a4ac01b 2861/**
2862 * Given a discussion object that is being moved to forumid,
2863 * this function checks all posts in that discussion
2864 * for attachments, and if any are found, these are
2865 * moved to the new forum directory.
2866 */
cc2b7ea5 2867function forum_move_attachments($discussion, $forumid) {
cc2b7ea5 2868
2869 global $CFG;
2870
18b8fbfa 2871 require_once($CFG->dirroot.'/lib/uploadlib.php');
2872
cc2b7ea5 2873 $return = true;
2874
2875 if ($posts = get_records_select("forum_posts", "discussion = '$discussion->id' AND attachment <> ''")) {
2876 foreach ($posts as $oldpost) {
2877 $oldpost->course = $discussion->course;
2878 $oldpost->forum = $discussion->forum;
2879 $oldpostdir = "$CFG->dataroot/".forum_file_area_name($oldpost);
2880 if (is_dir($oldpostdir)) {
2881 $newpost = $oldpost;
2882 $newpost->forum = $forumid;
03c9562b 2883 $newpostdir = forum_file_area_name($newpost);
2884 // take off the last directory because otherwise we're renaming to a directory that already exists
2885 // and this is unhappy in certain situations, eg over an nfs mount and potentially on windows too.
2886 make_upload_directory(substr($newpostdir,0,strrpos($newpostdir,'/')));
2887 $newpostdir = $CFG->dataroot.'/'.forum_file_area_name($newpost);
18b8fbfa 2888 $files = get_directory_list($oldpostdir); // get it before we rename it.
cc2b7ea5 2889 if (! @rename($oldpostdir, $newpostdir)) {
2890 $return = false;
2891 }
18b8fbfa 2892 foreach ($files as $file) {
2893 clam_change_log($oldpostdir.'/'.$file,$newpostdir.'/'.$file);
2894 }
cc2b7ea5 2895 }
2896 }
2897 }
2898 return $return;
2899}
2900
0a4ac01b 2901/**
2902 * if return=html, then return a html string.
2903 * if return=text, then return a text-only string.
2904 * otherwise, print HTML for non-images, and return image HTML
2905 */
7f6689e4 2906function forum_print_attachments($post, $return=NULL) {
7f6689e4 2907
2908 global $CFG;
2909
2910 $filearea = forum_file_area_name($post);
2911
72d497d4 2912 $imagereturn = "";
2913 $output = "";
2914
7f6689e4 2915 if ($basedir = forum_file_area($post)) {
2916 if ($files = get_directory_list($basedir)) {
2917 $strattachment = get_string("attachment", "forum");
2918 foreach ($files as $file) {
2919 $icon = mimeinfo("icon", $file);
feaf5d06 2920 $type = mimeinfo("type", $file);
7f6689e4 2921 if ($CFG->slasharguments) {
2a1975cb 2922 $ffurl = "$CFG->wwwroot/file.php/$filearea/$file";
7f6689e4 2923 } else {
2a1975cb 2924 $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
7f6689e4 2925 }
0d905d9f 2926 $image = "<img src=\"$CFG->pixpath/f/$icon\" class=\"icon\" alt=\"\" />";
7f6689e4 2927
2928 if ($return == "html") {
2a1975cb 2929 $output .= "<a href=\"$ffurl\">$image</a> ";
2930 $output .= "<a href=\"$ffurl\">$file</a><br />";
7f6689e4 2931
2932 } else if ($return == "text") {
2a1975cb 2933 $output .= "$strattachment $file:\n$ffurl\n";
7f6689e4 2934
2935 } else {
feaf5d06 2936 if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) { // Image attachments don't get printed as links
2a1975cb 2937 $imagereturn .= "<br /><img src=\"$ffurl\" alt=\"\" />";
72d497d4 2938 } else {
2a1975cb 2939 echo "<a href=\"$ffurl\">$image</a> ";
bce7a133 2940 echo filter_text("<a href=\"$ffurl\">$file</a><br />");
72d497d4 2941 }
7f6689e4 2942 }
2943 }
2944 }
2945 }
72d497d4 2946
7f6689e4 2947 if ($return) {
2948 return $output;
2949 }
72d497d4 2950
2951 return $imagereturn;
7f6689e4 2952}
db290a6e 2953/**
e3ff14ca 2954 * If successful, this function returns the name of the file
db290a6e 2955 * @param $post is a full post record, including course and forum
2956 * @param $newfile is a full upload array from $_FILES
2957 * @param $message is a string to hold the messages.
e3ff14ca 2958 */
7f6689e4 2959
0a4ac01b 2960/**
3a5e1d06 2961 *
0a4ac01b 2962 */
db290a6e 2963function forum_add_attachment($post, $inputname,&$message) {
7f6689e4 2964
9dd0b378 2965 global $CFG;
2966
4909e176 2967 if (!$forum = get_record("forum", "id", $post->forum)) {
2968 return "";
2969 }
2970
2971 if (!$course = get_record("course", "id", $forum->course)) {
2972 return "";
2973 }
2974
5ddaa2e2 2975 require_once($CFG->dirroot.'/lib/uploadlib.php');
db290a6e 2976 $um = new upload_manager($inputname,true,false,$course,false,$forum->maxbytes,true,true);
5ddaa2e2 2977 $dir = forum_file_area_name($post);
2978 if ($um->process_file_uploads($dir)) {
db290a6e 2979 $message .= $um->get_errors();
5ddaa2e2 2980 return $um->get_new_filename();
7f6689e4 2981 }
db290a6e 2982 $message .= $um->get_errors();
feaf5d06 2983 return null;
7f6689e4 2984}
501cdbd8 2985
0a4ac01b 2986/**
3a5e1d06 2987 *
0a4ac01b 2988 */
db290a6e 2989function forum_add_new_post($post,&$message) {
501cdbd8 2990
f37da850 2991 global $USER, $CFG;
e3ff14ca 2992
ffe11640 2993 $post->created = $post->modified = time();
501cdbd8 2994 $post->mailed = "0";
a56f0d60 2995 $post->userid = $USER->id;
7f6689e4 2996 $post->attachment = "";
2997
65b0e537 2998 if (! $post->id = insert_record("forum_posts", $post)) {
7f6689e4 2999 return false;
3000 }
3001
db290a6e 3002 if ($post->attachment = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 3003 set_field("forum_posts", "attachment", $post->attachment, "id", $post->id);
3004 }
29507631 3005
3006 // Update discussion modified date
3007 set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
016cd6af 3008 set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
65b0e537 3009
eaf50aef 3010 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 3011 forum_tp_mark_post_read($post->userid, $post, $post->forum);
3012 }
3013
7f6689e4 3014 return $post->id;
501cdbd8 3015}
3016
0a4ac01b 3017/**
3a5e1d06 3018 *
0a4ac01b 3019 */
db290a6e 3020function forum_update_post($post,&$message) {
501cdbd8 3021
f37da850 3022 global $USER, $CFG;
a56f0d60 3023
ffe11640 3024 $post->modified = time();
0936de64 3025
0ab85112 3026 if (!$post->parent) { // Post is a discussion starter - update discussion title too
3027 set_field("forum_discussions", "name", $post->subject, "id", $post->discussion);
3028 }
29507631 3029
db290a6e 3030 if ($newfilename = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 3031 $post->attachment = $newfilename;
3032 } else {
3033 unset($post->attachment);
3034 }
29507631 3035
3036 // Update discussion modified date
3037 set_field("forum_discussions", "timemodified", $post->modified, "id", $post->discussion);
016cd6af 3038 set_field("forum_discussions", "usermodified", $post->userid, "id", $post->discussion);
29507631 3039
eaf50aef 3040 if (forum_tp_can_track_forums($post->forum) && forum_tp_is_tracked($post->forum)) {
f37da850 3041 forum_tp_mark_post_read($post->userid, $post, $post->forum);
3042 }
3043
ffe11640 3044 return update_record("forum_posts", $post);
501cdbd8 3045}
3046
0a4ac01b 3047/**
3048 * Given an object containing all the necessary data,
3049 * create a new discussion and return the id
3050 */
db290a6e 3051function forum_add_discussion($discussion,&$message) {
501cdbd8 3052
f37da850 3053 GLOBAL $USER, $CFG;
501cdbd8 3054
3055 $timenow = time();
3056
65b0e537 3057 // The first post is stored as a real post, and linked
501cdbd8 3058 // to from the discuss entry.
3059
0b5a80a1 3060 $post = new object();
501cdbd8 3061 $post->discussion = 0;
3062 $post->parent = 0;
ebc3bd2b 3063 $post->userid = $USER->id;
501cdbd8 3064 $post->created = $timenow;
3065 $post->modified = $timenow;
3066 $post->mailed = 0;
3067 $post->subject = $discussion->name;
3068 $post->message = $discussion->intro;
7f6689e4 3069 $post->attachment = "";
3070 $post->forum = $discussion->forum;
3071 $post->course = $discussion->course;
9f0b8269 3072 $post->format = $discussion->format;
41547057 3073 $post->mailnow = $discussion->mailnow;
501cdbd8 3074
3075 if (! $post->id = insert_record("forum_posts", $post) ) {
3076 return 0;
3077 }
3078
db290a6e 3079 if ($post->attachment = forum_add_attachment($post, 'attachment',$message)) {
7f6689e4 3080 set_field("forum_posts", "attachment", $post->attachment, "id", $post->id); //ignore errors
3081 }
3082
65b0e537 3083 // Now do the main entry for the discussion,
02509fe6 3084 // linking to this first post
04eba58f 3085
caadf009 3086 $discussion->firstpost = $post->id;
3087 $discussion->timemodified = $timenow;
016cd6af 3088