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