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