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