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