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