MDL-17914: Conditional activities should check that available dates in module form...
[moodle.git] / course / lib.php
CommitLineData
e4027ac9 1<?php // $Id$
97c270e9 2 // Library of useful functions
f9903ed0 3
4e781c7b 4require_once($CFG->libdir.'/completionlib.php');
f9903ed0 5
92890025 6define('COURSE_MAX_LOG_DISPLAY', 150); // days
7define('COURSE_MAX_LOGS_PER_PAGE', 1000); // records
8define('COURSE_LIVELOG_REFRESH', 60); // Seconds
9define('COURSE_MAX_RECENT_PERIOD', 172800); // Two days, in seconds
10define('COURSE_MAX_SUMMARIES_PER_PAGE', 10); // courses
950c35a9 11define('COURSE_MAX_COURSES_PER_DROPDOWN',1000); // max courses in log dropdown before switching to optional
92890025 12define('COURSE_MAX_USERS_PER_DROPDOWN',1000); // max users in log dropdown before switching to optional
220a90c5 13define('FRONTPAGENEWS', '0');
14define('FRONTPAGECOURSELIST', '1');
15define('FRONTPAGECATEGORYNAMES', '2');
16define('FRONTPAGETOPICONLY', '3');
17define('FRONTPAGECATEGORYCOMBO', '4');
6f24e48e 18define('FRONTPAGECOURSELIMIT', 200); // maximum number of courses displayed on the frontpage
19define('EXCELROWS', 65535);
20define('FIRSTUSEDEXCELROW', 3);
60fdc714 21
89bfeee0 22define('MOD_CLASS_ACTIVITY', 0);
23define('MOD_CLASS_RESOURCE', 1);
24
f9903ed0 25
600149be 26function make_log_url($module, $url) {
27 switch ($module) {
bd7be234 28 case 'course':
29 case 'file':
30 case 'login':
31 case 'lib':
32 case 'admin':
bd7be234 33 case 'calendar':
bd5d0ce5 34 case 'mnet course':
11003188 35 if (strpos($url, '../') === 0) {
36 $url = ltrim($url, '.');
37 } else {
38 $url = "/course/$url";
39 }
bd5d0ce5 40 break;
01d5d399 41 case 'user':
bd7be234 42 case 'blog':
11003188 43 $url = "/$module/$url";
600149be 44 break;
bd7be234 45 case 'upload':
11003188 46 $url = $url;
c80b7585 47 break;
38fb8190 48 case 'coursetags':
11003188 49 $url = '/'.$url;
38fb8190 50 break;
bd7be234 51 case 'library':
52 case '':
11003188 53 $url = '/';
de2dfe68 54 break;
4597d533 55 case 'message':
11003188 56 $url = "/message/$url";
57 break;
58 case 'notes':
59 $url = "/notes/$url";
4597d533 60 break;
600149be 61 default:
11003188 62 $url = "/mod/$module/$url";
600149be 63 break;
64 }
11003188 65
66 //now let's sanitise urls - there might be some ugly nasties:-(
67 $parts = explode('?', $url);
68 $script = array_shift($parts);
69 if (strpos($script, 'http') === 0) {
70 $script = clean_param($script, PARAM_URL);
71 } else {
72 $script = clean_param($script, PARAM_PATH);
73 }
74
75 $query = '';
76 if ($parts) {
77 $query = implode('', $parts);
78 $query = str_replace('&amp;', '&', $query); // both & and &amp; are stored in db :-|
79 $parts = explode('&', $query);
80 $eq = urlencode('=');
81 foreach ($parts as $key=>$part) {
82 $part = urlencode(urldecode($part));
83 $part = str_replace($eq, '=', $part);
84 $parts[$key] = $part;
85 }
86 $query = '?'.implode('&amp;', $parts);
87 }
88
89 return $script.$query;
600149be 90}
91
92890025 92
c215b32b 93function build_mnet_logs_array($hostid, $course, $user=0, $date=0, $order="l.time ASC", $limitfrom='', $limitnum='',
94 $modname="", $modid=0, $modaction="", $groupid=0) {
cb6fec1f 95 global $CFG, $DB;
c215b32b 96
97 // It is assumed that $date is the GMT time of midnight for that day,
98 // and so the next 86400 seconds worth of logs are printed.
99
100 /// Setup for group handling.
238c0dd9 101
102 // TODO: I don't understand group/context/etc. enough to be able to do
c215b32b 103 // something interesting with it here
104 // What is the context of a remote course?
238c0dd9 105
c215b32b 106 /// If the group mode is separate, and this user does not have editing privileges,
107 /// then only the user's group can be viewed.
108 //if ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
109 // $groupid = get_current_group($course->id);
110 //}
111 /// If this course doesn't have groups, no groupid can be specified.
112 //else if (!$course->groupmode) {
113 // $groupid = 0;
114 //}
cb6fec1f 115
116 $ILIKE = $DB->sql_ilike();
117
c215b32b 118 $groupid = 0;
119
120 $joins = array();
121
cb6fec1f 122 $qry = "SELECT l.*, u.firstname, u.lastname, u.picture
123 FROM {mnet_log} l
124 LEFT JOIN {user} u ON l.userid = u.id
125 WHERE ";
126 $params = array();
127
128 $where .= "l.hostid = :hostid";
129 $params['hostid'] = $hostid;
c215b32b 130
131 // TODO: Is 1 really a magic number referring to the sitename?
cb6fec1f 132 if ($course != SITEID || $modid != 0) {
133 $where .= " AND l.course=:courseid";
134 $params['courseid'] = $course;
c215b32b 135 }
136
137 if ($modname) {
cb6fec1f 138 $where .= " AND l.module = :modname";
139 $params['modname'] = $modname;
c215b32b 140 }
141
142 if ('site_errors' === $modid) {
cb6fec1f 143 $where .= " AND ( l.action='error' OR l.action='infected' )";
c215b32b 144 } else if ($modid) {
238c0dd9 145 //TODO: This assumes that modids are the same across sites... probably
c215b32b 146 //not true
cb6fec1f 147 $where .= " AND l.cmid = :modid";
148 $params['modid'] = $modid;
c215b32b 149 }
150
151 if ($modaction) {
152 $firstletter = substr($modaction, 0, 1);
c659559f 153 if (preg_match('/[[:alpha:]]/', $firstletter)) {
cb6fec1f 154 $where .= " AND lower(l.action) $ILIKE :modaction";
155 $params['modaction'] = "%$modaction%";
c215b32b 156 } else if ($firstletter == '-') {
cb6fec1f 157 $where .= " AND lower(l.action) NOT $ILIKE :modaction";
158 $params['modaction'] = "%$modaction%";
c215b32b 159 }
160 }
161
162 if ($user) {
cb6fec1f 163 $where .= " AND l.userid = :user";
164 $params['user'] = $user;
c215b32b 165 }
166
167 if ($date) {
168 $enddate = $date + 86400;
cb6fec1f 169 $where .= " AND l.time > :date AND l.time < :enddate";
170 $params['date'] = $date;
171 $params['enddate'] = $enddate;
c215b32b 172 }
173
174 $result = array();
cb6fec1f 175 $result['totalcount'] = $DB->count_records_sql("SELECT COUNT('x') FROM {mnet_log} l WHERE $where", $params);
c215b32b 176 if(!empty($result['totalcount'])) {
cb6fec1f 177 $where .= " ORDER BY $order";
178 $result['logs'] = $DB->get_records_sql("$qry $where", $params, $limitfrom, $limitnum);
c215b32b 179 } else {
180 $result['logs'] = array();
181 }
182 return $result;
183}
184
92890025 185function build_logs_array($course, $user=0, $date=0, $order="l.time ASC", $limitfrom='', $limitnum='',
186 $modname="", $modid=0, $modaction="", $groupid=0) {
c3df0901 187 global $DB;
e0161bff 188 // It is assumed that $date is the GMT time of midnight for that day,
189 // and so the next 86400 seconds worth of logs are printed.
f9903ed0 190
69c76405 191 /// Setup for group handling.
264867fd 192
69c76405 193 /// If the group mode is separate, and this user does not have editing privileges,
194 /// then only the user's group can be viewed.
3924b988 195 if ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
69c76405 196 $groupid = get_current_group($course->id);
197 }
198 /// If this course doesn't have groups, no groupid can be specified.
199 else if (!$course->groupmode) {
200 $groupid = 0;
201 }
202
e0161bff 203 $joins = array();
c3df0901 204 $oarams = array();
a2ab3b05 205
e15ef260 206 if ($course->id != SITEID || $modid != 0) {
c3df0901 207 $joins[] = "l.course = :courseid";
208 $params['courseid'] = $course->id;
e15ef260 209 }
f9903ed0 210
c469a7ef 211 if ($modname) {
c3df0901 212 $joins[] = "l.module = :modname";
238c0dd9 213 $params['modname'] = $modname;
f24cffb9 214 }
215
e21922f0 216 if ('site_errors' === $modid) {
bf35eb15 217 $joins[] = "( l.action='error' OR l.action='infected' )";
e21922f0 218 } else if ($modid) {
c3df0901 219 $joins[] = "l.cmid = :modid";
220 $params['modid'] = $modid;
69d79bc3 221 }
222
223 if ($modaction) {
c3df0901 224 $ILIKE = $DB->sql_ilike();
ee35e0b8 225 $firstletter = substr($modaction, 0, 1);
c659559f 226 if (preg_match('/[[:alpha:]]/', $firstletter)) {
c3df0901 227 $joins[] = "l.action $ILIKE :modaction";
228 $params['modaction'] = '%'.$modaction.'%';
ee35e0b8 229 } else if ($firstletter == '-') {
c3df0901 230 $joins[] = "l.action NOT $ILIKE :modaction";
231 $params['modaction'] = '%'.substr($modaction, 1).'%';
ee35e0b8 232 }
f24cffb9 233 }
234
238c0dd9 235
69c76405 236 /// Getting all members of a group.
237 if ($groupid and !$user) {
62d63838 238 if ($gusers = groups_get_members($groupid)) {
239 $gusers = array_keys($gusers);
1e95d7b7 240 $joins[] = 'l.userid IN (' . implode(',', $gusers) . ')';
241 } else {
05a33439 242 $joins[] = 'l.userid = 0'; // No users in groups, so we want something that will always be false.
69c76405 243 }
244 }
245 else if ($user) {
c3df0901 246 $joins[] = "l.userid = :userid";
247 $params['userid'] = $user;
f9903ed0 248 }
249
250 if ($date) {
251 $enddate = $date + 86400;
c3df0901 252 $joins[] = "l.time > :date AND l.time < :enddate";
253 $params['date'] = $date;
254 $params['enddate'] = $enddate;
f9903ed0 255 }
256
1e95d7b7 257 $selector = implode(' AND ', $joins);
e0161bff 258
d09f3c80 259 $totalcount = 0; // Initialise
92890025 260 $result = array();
c3df0901 261 $result['logs'] = get_logs($selector, $params, $order, $limitfrom, $limitnum, $totalcount);
92890025 262 $result['totalcount'] = $totalcount;
263 return $result;
264}
264867fd 265
266
92890025 267function print_log($course, $user=0, $date=0, $order="l.time ASC", $page=0, $perpage=100,
268 $url="", $modname="", $modid=0, $modaction="", $groupid=0) {
264867fd 269
cb6fec1f 270 global $CFG, $DB;
264867fd 271
92890025 272 if (!$logs = build_logs_array($course, $user, $date, $order, $page*$perpage, $perpage,
273 $modname, $modid, $modaction, $groupid)) {
f9903ed0 274 notify("No logs found!");
275 print_footer($course);
276 exit;
277 }
264867fd 278
ea49a66c 279 $courses = array();
280
92890025 281 if ($course->id == SITEID) {
282 $courses[0] = '';
bf221aca 283 if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) {
92890025 284 foreach ($ccc as $cc) {
bf221aca 285 $courses[$cc->id] = $cc->shortname;
92890025 286 }
287 }
ea49a66c 288 } else {
bf221aca 289 $courses[$course->id] = $course->shortname;
92890025 290 }
264867fd 291
92890025 292 $totalcount = $logs['totalcount'];
f9903ed0 293 $count=0;
2eb68e6f 294 $ldcache = array();
f9903ed0 295 $tt = getdate(time());
296 $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
1c0200e0 297
dcde9f02 298 $strftimedatetime = get_string("strftimedatetime");
299
5577ceb3 300 echo "<div class=\"info\">\n";
519d369f 301 print_string("displayingrecords", "", $totalcount);
5577ceb3 302 echo "</div>\n";
1c0200e0 303
8f0cd6ef 304 print_paging_bar($totalcount, $page, $perpage, "$url&amp;perpage=$perpage&amp;");
519d369f 305
38dc85bf 306 echo '<table class="logtable generalbox boxaligncenter" summary="">'."\n";
56595370 307 // echo "<table class=\"logtable\" cellpadding=\"3\" cellspacing=\"0\" summary=\"\">\n";
21283ddc 308 echo "<tr>";
1548978d 309 if ($course->id == SITEID) {
54926e78 310 echo "<th class=\"c0 header\" scope=\"col\">".get_string('course')."</th>\n";
1548978d 311 }
54926e78 312 echo "<th class=\"c1 header\" scope=\"col\">".get_string('time')."</th>\n";
313 echo "<th class=\"c2 header\" scope=\"col\">".get_string('ip_address')."</th>\n";
d6cc2341 314 echo "<th class=\"c3 header\" scope=\"col\">".get_string('fullnamecourse')."</th>\n";
54926e78 315 echo "<th class=\"c4 header\" scope=\"col\">".get_string('action')."</th>\n";
316 echo "<th class=\"c5 header\" scope=\"col\">".get_string('info')."</th>\n";
21283ddc 317 echo "</tr>\n";
1548978d 318
1e95d7b7 319 // Make sure that the logs array is an array, even it is empty, to avoid warnings from the foreach.
2b2d182a 320 if (empty($logs['logs'])) {
1e95d7b7 321 $logs['logs'] = array();
2b2d182a 322 }
238c0dd9 323
1548978d 324 $row = 1;
92890025 325 foreach ($logs['logs'] as $log) {
600149be 326
1548978d 327 $row = ($row + 1) % 2;
328
2eb68e6f 329 if (isset($ldcache[$log->module][$log->action])) {
330 $ld = $ldcache[$log->module][$log->action];
331 } else {
cb6fec1f 332 $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
2eb68e6f 333 $ldcache[$log->module][$log->action] = $ld;
334 }
edf3ef00 335 if ($ld && is_numeric($log->info)) {
181b888e 336 // ugly hack to make sure fullname is shown correctly
cb6fec1f 337 if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
338 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
181b888e 339 } else {
cb6fec1f 340 $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info));
181b888e 341 }
600149be 342 }
343
264867fd 344 //Filter log->info
c8b0a50b 345 $log->info = format_string($log->info);
346
6c5a2108 347 // If $log->url has been trimmed short by the db size restriction
348 // code in add_to_log, keep a note so we don't add a link to a broken url
349 $tl=textlib_get_instance();
350 $brokenurl=($tl->strlen($log->url)==100 && $tl->substr($log->url,97)=='...');
351
1548978d 352 echo '<tr class="r'.$row.'">';
353 if ($course->id == SITEID) {
56595370 354 echo "<td class=\"cell c0\">\n";
bd5d0ce5 355 if (empty($log->course)) {
05a33439 356 echo get_string('site') . "\n";
bd5d0ce5 357 } else {
bf221aca 358 echo " <a href=\"{$CFG->wwwroot}/course/view.php?id={$log->course}\">". format_string($courses[$log->course])."</a>\n";
bd5d0ce5 359 }
21283ddc 360 echo "</td>\n";
720a43ce 361 }
56595370 362 echo "<td class=\"cell c1\" align=\"right\">".userdate($log->time, '%a').
21283ddc 363 ' '.userdate($log->time, $strftimedatetime)."</td>\n";
56595370 364 echo "<td class=\"cell c2\">\n";
7c09710c 365 link_to_popup_window("/iplookup/index.php?ip=$log->ip&amp;user=$log->userid", 'iplookup',$log->ip, 440, 700);
21283ddc 366 echo "</td>\n";
bf221aca 367 $fullname = fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id)));
56595370 368 echo "<td class=\"cell c3\">\n";
bf221aca 369 echo " <a href=\"$CFG->wwwroot/user/view.php?id={$log->userid}&amp;course={$log->course}\">$fullname</a>\n";
21283ddc 370 echo "</td>\n";
56595370 371 echo "<td class=\"cell c4\">\n";
6c5a2108 372 $displayaction="$log->module $log->action";
373 if($brokenurl) {
374 echo $displayaction;
375 } else {
376 link_to_popup_window( make_log_url($log->module,$log->url), 'fromloglive',$displayaction, 440, 700);
377 }
21283ddc 378 echo "</td>\n";;
56595370 379 echo "<td class=\"cell c5\">{$log->info}</td>\n";
21283ddc 380 echo "</tr>\n";
f9903ed0 381 }
21283ddc 382 echo "</table>\n";
519d369f 383
8f0cd6ef 384 print_paging_bar($totalcount, $page, $perpage, "$url&amp;perpage=$perpage&amp;");
f9903ed0 385}
386
387
c215b32b 388function print_mnet_log($hostid, $course, $user=0, $date=0, $order="l.time ASC", $page=0, $perpage=100,
389 $url="", $modname="", $modid=0, $modaction="", $groupid=0) {
238c0dd9 390
cb6fec1f 391 global $CFG, $DB;
238c0dd9 392
c215b32b 393 if (!$logs = build_mnet_logs_array($hostid, $course, $user, $date, $order, $page*$perpage, $perpage,
394 $modname, $modid, $modaction, $groupid)) {
395 notify("No logs found!");
396 print_footer($course);
397 exit;
398 }
238c0dd9 399
c215b32b 400 if ($course->id == SITEID) {
401 $courses[0] = '';
402 if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname,c.visible')) {
403 foreach ($ccc as $cc) {
404 $courses[$cc->id] = $cc->shortname;
405 }
406 }
407 }
238c0dd9 408
c215b32b 409 $totalcount = $logs['totalcount'];
410 $count=0;
411 $ldcache = array();
412 $tt = getdate(time());
413 $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
414
415 $strftimedatetime = get_string("strftimedatetime");
416
5577ceb3 417 echo "<div class=\"info\">\n";
c215b32b 418 print_string("displayingrecords", "", $totalcount);
5577ceb3 419 echo "</div>\n";
c215b32b 420
421 print_paging_bar($totalcount, $page, $perpage, "$url&amp;perpage=$perpage&amp;");
422
5577ceb3 423 echo "<table class=\"logtable\" cellpadding=\"3\" cellspacing=\"0\">\n";
c215b32b 424 echo "<tr>";
425 if ($course->id == SITEID) {
426 echo "<th class=\"c0 header\">".get_string('course')."</th>\n";
427 }
428 echo "<th class=\"c1 header\">".get_string('time')."</th>\n";
429 echo "<th class=\"c2 header\">".get_string('ip_address')."</th>\n";
d6cc2341 430 echo "<th class=\"c3 header\">".get_string('fullnamecourse')."</th>\n";
c215b32b 431 echo "<th class=\"c4 header\">".get_string('action')."</th>\n";
432 echo "<th class=\"c5 header\">".get_string('info')."</th>\n";
433 echo "</tr>\n";
434
435 if (empty($logs['logs'])) {
436 echo "</table>\n";
437 return;
438 }
439
440 $row = 1;
441 foreach ($logs['logs'] as $log) {
238c0dd9 442
c215b32b 443 $log->info = $log->coursename;
444 $row = ($row + 1) % 2;
445
446 if (isset($ldcache[$log->module][$log->action])) {
447 $ld = $ldcache[$log->module][$log->action];
448 } else {
6bb08163 449 $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
c215b32b 450 $ldcache[$log->module][$log->action] = $ld;
451 }
452 if (0 && $ld && !empty($log->info)) {
453 // ugly hack to make sure fullname is shown correctly
cb6fec1f 454 if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
455 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
c215b32b 456 } else {
cb6fec1f 457 $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info));
c215b32b 458 }
459 }
460
238c0dd9 461 //Filter log->info
c215b32b 462 $log->info = format_string($log->info);
463
c215b32b 464 echo '<tr class="r'.$row.'">';
465 if ($course->id == SITEID) {
5577ceb3 466 echo "<td class=\"r$row c0\" >\n";
c215b32b 467 echo " <a href=\"{$CFG->wwwroot}/course/view.php?id={$log->course}\">".$courses[$log->course]."</a>\n";
468 echo "</td>\n";
469 }
5577ceb3 470 echo "<td class=\"r$row c1\" align=\"right\">".userdate($log->time, '%a').
c215b32b 471 ' '.userdate($log->time, $strftimedatetime)."</td>\n";
5577ceb3 472 echo "<td class=\"r$row c2\" >\n";
c215b32b 473 link_to_popup_window("/iplookup/index.php?ip=$log->ip&amp;user=$log->userid", 'iplookup',$log->ip, 400, 700);
474 echo "</td>\n";
475 $fullname = fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id)));
5577ceb3 476 echo "<td class=\"r$row c3\" >\n";
c215b32b 477 echo " <a href=\"$CFG->wwwroot/user/view.php?id={$log->userid}\">$fullname</a>\n";
478 echo "</td>\n";
5577ceb3 479 echo "<td class=\"r$row c4\">\n";
c215b32b 480 echo $log->action .': '.$log->module;
481 echo "</td>\n";;
5577ceb3 482 echo "<td class=\"r$row c5\">{$log->info}</td>\n";
c215b32b 483 echo "</tr>\n";
484 }
485 echo "</table>\n";
486
487 print_paging_bar($totalcount, $page, $perpage, "$url&amp;perpage=$perpage&amp;");
488}
489
490
92890025 491function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
492 $modid, $modaction, $groupid) {
cb6fec1f 493 global $DB;
4068bedb 494
954fdb42 495 $text = get_string('course')."\t".get_string('time')."\t".get_string('ip_address')."\t".
d6cc2341 496 get_string('fullnamecourse')."\t".get_string('action')."\t".get_string('info');
264867fd 497
954fdb42 498 if (!$logs = build_logs_array($course, $user, $date, $order, '', '',
92890025 499 $modname, $modid, $modaction, $groupid)) {
500 return false;
501 }
264867fd 502
ea49a66c 503 $courses = array();
504
92890025 505 if ($course->id == SITEID) {
506 $courses[0] = '';
507 if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) {
508 foreach ($ccc as $cc) {
509 $courses[$cc->id] = $cc->shortname;
510 }
511 }
ea49a66c 512 } else {
513 $courses[$course->id] = $course->shortname;
92890025 514 }
264867fd 515
92890025 516 $count=0;
517 $ldcache = array();
518 $tt = getdate(time());
519 $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
520
521 $strftimedatetime = get_string("strftimedatetime");
92890025 522
954fdb42 523 $filename = 'logs_'.userdate(time(),get_string('backupnameformat'),99,false);
524 $filename .= '.txt';
264867fd 525 header("Content-Type: application/download\n");
954fdb42 526 header("Content-Disposition: attachment; filename=$filename");
527 header("Expires: 0");
528 header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
529 header("Pragma: public");
530
531 echo get_string('savedat').userdate(time(), $strftimedatetime)."\n";
532 echo $text;
533
2b2d182a 534 if (empty($logs['logs'])) {
535 return true;
536 }
537
954fdb42 538 foreach ($logs['logs'] as $log) {
539 if (isset($ldcache[$log->module][$log->action])) {
540 $ld = $ldcache[$log->module][$log->action];
541 } else {
6bb08163 542 $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
954fdb42 543 $ldcache[$log->module][$log->action] = $ld;
544 }
545 if ($ld && !empty($log->info)) {
546 // ugly hack to make sure fullname is shown correctly
cb6fec1f 547 if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
548 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
954fdb42 549 } else {
cb6fec1f 550 $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info));
954fdb42 551 }
552 }
553
264867fd 554 //Filter log->info
954fdb42 555 $log->info = format_string($log->info);
954fdb42 556 $log->info = strip_tags(urldecode($log->info)); // Some XSS protection
954fdb42 557
558 $firstField = $courses[$log->course];
1c45e42e 559 $fullname = fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id)));
954fdb42 560 $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action, $log->info);
561 $text = implode("\t", $row);
562 echo $text." \n";
563 }
564 return true;
92890025 565}
566
567
568function print_log_xls($course, $user, $date, $order='l.time DESC', $modname,
569 $modid, $modaction, $groupid) {
264867fd 570
cb6fec1f 571 global $CFG, $DB;
92890025 572
954fdb42 573 require_once("$CFG->libdir/excellib.class.php");
264867fd 574
954fdb42 575 if (!$logs = build_logs_array($course, $user, $date, $order, '', '',
92890025 576 $modname, $modid, $modaction, $groupid)) {
577 return false;
578 }
264867fd 579
ea49a66c 580 $courses = array();
581
92890025 582 if ($course->id == SITEID) {
583 $courses[0] = '';
584 if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) {
585 foreach ($ccc as $cc) {
586 $courses[$cc->id] = $cc->shortname;
587 }
588 }
ea49a66c 589 } else {
590 $courses[$course->id] = $course->shortname;
92890025 591 }
264867fd 592
92890025 593 $count=0;
594 $ldcache = array();
595 $tt = getdate(time());
596 $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
597
598 $strftimedatetime = get_string("strftimedatetime");
92890025 599
954fdb42 600 $nroPages = ceil(count($logs)/(EXCELROWS-FIRSTUSEDEXCELROW+1));
601 $filename = 'logs_'.userdate(time(),get_string('backupnameformat'),99,false);
602 $filename .= '.xls';
264867fd 603
92890025 604 $workbook = new MoodleExcelWorkbook('-');
605 $workbook->send($filename);
264867fd 606
954fdb42 607 $worksheet = array();
608 $headers = array(get_string('course'), get_string('time'), get_string('ip_address'),
d6cc2341 609 get_string('fullnamecourse'), get_string('action'), get_string('info'));
264867fd 610
954fdb42 611 // Creating worksheets
612 for ($wsnumber = 1; $wsnumber <= $nroPages; $wsnumber++) {
0a013367 613 $sheettitle = get_string('logs').' '.$wsnumber.'-'.$nroPages;
954fdb42 614 $worksheet[$wsnumber] =& $workbook->add_worksheet($sheettitle);
615 $worksheet[$wsnumber]->set_column(1, 1, 30);
616 $worksheet[$wsnumber]->write_string(0, 0, get_string('savedat').
617 userdate(time(), $strftimedatetime));
618 $col = 0;
619 foreach ($headers as $item) {
620 $worksheet[$wsnumber]->write(FIRSTUSEDEXCELROW-1,$col,$item,'');
621 $col++;
622 }
623 }
624
2b2d182a 625 if (empty($logs['logs'])) {
626 $workbook->close();
627 return true;
628 }
629
954fdb42 630 $formatDate =& $workbook->add_format();
631 $formatDate->set_num_format(get_string('log_excel_date_format'));
632
633 $row = FIRSTUSEDEXCELROW;
634 $wsnumber = 1;
635 $myxls =& $worksheet[$wsnumber];
636 foreach ($logs['logs'] as $log) {
637 if (isset($ldcache[$log->module][$log->action])) {
638 $ld = $ldcache[$log->module][$log->action];
639 } else {
cb6fec1f 640 $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
954fdb42 641 $ldcache[$log->module][$log->action] = $ld;
642 }
643 if ($ld && !empty($log->info)) {
644 // ugly hack to make sure fullname is shown correctly
cb6fec1f 645 if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
646 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
954fdb42 647 } else {
cb6fec1f 648 $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info));
954fdb42 649 }
650 }
651
652 // Filter log->info
653 $log->info = format_string($log->info);
654 $log->info = strip_tags(urldecode($log->info)); // Some XSS protection
655
656 if ($nroPages>1) {
657 if ($row > EXCELROWS) {
658 $wsnumber++;
659 $myxls =& $worksheet[$wsnumber];
660 $row = FIRSTUSEDEXCELROW;
661 }
662 }
264867fd 663
954fdb42 664 $myxls->write($row, 0, $courses[$log->course], '');
665 // Excel counts from 1/1/1900
666 $excelTime=25569+$log->time/(3600*24);
667 $myxls->write($row, 1, $excelTime, $formatDate);
668 $myxls->write($row, 2, $log->ip, '');
1c45e42e 669 $fullname = fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id)));
954fdb42 670 $myxls->write($row, 3, $fullname, '');
671 $myxls->write($row, 4, $log->module.' '.$log->action, '');
672 $myxls->write($row, 5, $log->info, '');
264867fd 673
954fdb42 674 $row++;
675 }
676
677 $workbook->close();
ea49a66c 678 return true;
679}
680
681function print_log_ods($course, $user, $date, $order='l.time DESC', $modname,
682 $modid, $modaction, $groupid) {
683
cb6fec1f 684 global $CFG, $DB;
ea49a66c 685
686 require_once("$CFG->libdir/odslib.class.php");
687
688 if (!$logs = build_logs_array($course, $user, $date, $order, '', '',
689 $modname, $modid, $modaction, $groupid)) {
690 return false;
691 }
692
693 $courses = array();
694
695 if ($course->id == SITEID) {
696 $courses[0] = '';
697 if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) {
698 foreach ($ccc as $cc) {
699 $courses[$cc->id] = $cc->shortname;
700 }
701 }
702 } else {
703 $courses[$course->id] = $course->shortname;
704 }
705
706 $count=0;
707 $ldcache = array();
708 $tt = getdate(time());
709 $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]);
710
711 $strftimedatetime = get_string("strftimedatetime");
712
713 $nroPages = ceil(count($logs)/(EXCELROWS-FIRSTUSEDEXCELROW+1));
714 $filename = 'logs_'.userdate(time(),get_string('backupnameformat'),99,false);
715 $filename .= '.ods';
716
717 $workbook = new MoodleODSWorkbook('-');
718 $workbook->send($filename);
719
720 $worksheet = array();
721 $headers = array(get_string('course'), get_string('time'), get_string('ip_address'),
d6cc2341 722 get_string('fullnamecourse'), get_string('action'), get_string('info'));
ea49a66c 723
724 // Creating worksheets
725 for ($wsnumber = 1; $wsnumber <= $nroPages; $wsnumber++) {
0a013367 726 $sheettitle = get_string('logs').' '.$wsnumber.'-'.$nroPages;
ea49a66c 727 $worksheet[$wsnumber] =& $workbook->add_worksheet($sheettitle);
728 $worksheet[$wsnumber]->set_column(1, 1, 30);
729 $worksheet[$wsnumber]->write_string(0, 0, get_string('savedat').
730 userdate(time(), $strftimedatetime));
731 $col = 0;
732 foreach ($headers as $item) {
733 $worksheet[$wsnumber]->write(FIRSTUSEDEXCELROW-1,$col,$item,'');
734 $col++;
735 }
736 }
737
738 if (empty($logs['logs'])) {
739 $workbook->close();
740 return true;
741 }
742
743 $formatDate =& $workbook->add_format();
744 $formatDate->set_num_format(get_string('log_excel_date_format'));
745
746 $row = FIRSTUSEDEXCELROW;
747 $wsnumber = 1;
748 $myxls =& $worksheet[$wsnumber];
749 foreach ($logs['logs'] as $log) {
750 if (isset($ldcache[$log->module][$log->action])) {
751 $ld = $ldcache[$log->module][$log->action];
752 } else {
cb6fec1f 753 $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action));
ea49a66c 754 $ldcache[$log->module][$log->action] = $ld;
755 }
756 if ($ld && !empty($log->info)) {
757 // ugly hack to make sure fullname is shown correctly
7e60297f 758 if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) {
cb6fec1f 759 $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true);
ea49a66c 760 } else {
cb6fec1f 761 $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info));
ea49a66c 762 }
763 }
764
765 // Filter log->info
766 $log->info = format_string($log->info);
767 $log->info = strip_tags(urldecode($log->info)); // Some XSS protection
768
769 if ($nroPages>1) {
770 if ($row > EXCELROWS) {
771 $wsnumber++;
772 $myxls =& $worksheet[$wsnumber];
773 $row = FIRSTUSEDEXCELROW;
774 }
775 }
776
d81b7ffb 777 $myxls->write_string($row, 0, $courses[$log->course]);
778 $myxls->write_date($row, 1, $log->time);
779 $myxls->write_string($row, 2, $log->ip);
ea49a66c 780 $fullname = fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id)));
d81b7ffb 781 $myxls->write_string($row, 3, $fullname);
782 $myxls->write_string($row, 4, $log->module.' '.$log->action);
783 $myxls->write_string($row, 5, $log->info);
ea49a66c 784
785 $row++;
786 }
787
788 $workbook->close();
954fdb42 789 return true;
92890025 790}
791
92890025 792
c2cb4545 793function print_log_graph($course, $userid=0, $type="course.png", $date=0) {
a683deec 794 global $CFG, $USER;
c2cb4545 795 if (empty($CFG->gdversion)) {
796 echo "(".get_string("gdneed").")";
d887b5a7 797 } else {
a683deec 798 // MDL-10818, do not display broken graph when user has no permission to view graph
a2e4bf7f 799 if (has_capability('coursereport/log:view', get_context_instance(CONTEXT_COURSE, $course->id)) ||
a683deec 800 ($course->showreports and $USER->id == $userid)) {
801 echo '<img src="'.$CFG->wwwroot.'/course/report/log/graph.php?id='.$course->id.
802 '&amp;user='.$userid.'&amp;type='.$type.'&amp;date='.$date.'" alt="" />';
803 }
d887b5a7 804 }
805}
806
807
185cfb09 808function print_overview($courses) {
6bb08163 809 global $CFG, $USER, $DB;
0d6b9d4f 810
185cfb09 811 $htmlarray = array();
6bb08163 812 if ($modules = $DB->get_records('modules')) {
f8716988 813 foreach ($modules as $mod) {
814 if (file_exists(dirname(dirname(__FILE__)).'/mod/'.$mod->name.'/lib.php')) {
f461e8ec 815 include_once(dirname(dirname(__FILE__)).'/mod/'.$mod->name.'/lib.php');
f8716988 816 $fname = $mod->name.'_print_overview';
0d6b9d4f 817 if (function_exists($fname)) {
185cfb09 818 $fname($courses,$htmlarray);
0d6b9d4f 819 }
820 }
821 }
822 }
185cfb09 823 foreach ($courses as $course) {
fe5a1e23 824 print_simple_box_start('center', '100%', '', 5, "coursebox");
185cfb09 825 $linkcss = '';
826 if (empty($course->visible)) {
827 $linkcss = 'class="dimmed"';
828 }
6ba65fa0 829 print_heading('<a title="'. format_string($course->fullname).'" '.$linkcss.' href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">'. format_string($course->fullname).'</a>');
185cfb09 830 if (array_key_exists($course->id,$htmlarray)) {
831 foreach ($htmlarray[$course->id] as $modname => $html) {
832 echo $html;
833 }
834 }
835 print_simple_box_end();
836 }
0d6b9d4f 837}
838
839
cb6fec1f 840/**
841 * This function trawls through the logs looking for
842 * anything new since the user's last login
843 */
600149be 844function print_recent_activity($course) {
845 // $course is an object
cb6fec1f 846 global $CFG, $USER, $SESSION, $DB;
600149be 847
e2a3a0e7 848 $context = get_context_instance(CONTEXT_COURSE, $course->id);
2ac64806 849
dd97c328 850 $viewfullnames = has_capability('moodle/site:viewfullnames', $context);
851
852 $timestart = round(time() - COURSE_MAX_RECENT_PERIOD, -2); // better db caching for guests - 100 seconds
0f87cb1d 853
e2a3a0e7 854 if (!has_capability('moodle/legacy:guest', $context, NULL, false)) {
855 if (!empty($USER->lastcourseaccess[$course->id])) {
856 if ($USER->lastcourseaccess[$course->id] > $timestart) {
857 $timestart = $USER->lastcourseaccess[$course->id];
858 }
9e51847a 859 }
3d891989 860 }
0f87cb1d 861
de785682 862 echo '<div class="activitydate">';
27bf9e20 863 echo get_string('activitysince', '', userdate($timestart));
de785682 864 echo '</div>';
865 echo '<div class="activityhead">';
0f87cb1d 866
de785682 867 echo '<a href="'.$CFG->wwwroot.'/course/recent.php?id='.$course->id.'">'.get_string('recentactivityreport').'</a>';
0f87cb1d 868
5fc835a5 869 echo "</div>\n";
0f87cb1d 870
600149be 871 $content = false;
1b5910c4 872
dd97c328 873/// Firstly, have there been any new enrolments?
874
6c38b7e0 875 $users = get_recent_enrolments($course->id, $timestart);
1b5910c4 876
5fc835a5 877 //Accessibility: new users now appear in an <OL> list.
6c38b7e0 878 if ($users) {
27bf9e20 879 echo '<div class="newusers">';
dd97c328 880 print_headline(get_string("newusers").':', 3);
881 $content = true;
5fc835a5 882 echo "<ol class=\"list\">\n";
6c38b7e0 883 foreach ($users as $user) {
dd97c328 884 $fullname = fullname($user, $viewfullnames);
885 echo '<li class="name"><a href="'."$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a></li>\n";
600149be 886 }
5fc835a5 887 echo "</ol>\n</div>\n";
600149be 888 }
889
dd97c328 890/// Next, have there been any modifications to the course structure?
891
892 $modinfo =& get_fast_modinfo($course);
893
894 $changelist = array();
1b5910c4 895
cb6fec1f 896 $logs = $DB->get_records_select('log', "time > ? AND course = ? AND
897 module = 'course' AND
898 (action = 'add mod' OR action = 'update mod' OR action = 'delete mod')",
899 array($timestart, $course->id), "id ASC");
1b5910c4 900
901 if ($logs) {
dd97c328 902 $actions = array('add mod', 'update mod', 'delete mod');
903 $newgones = array(); // added and later deleted items
1b5910c4 904 foreach ($logs as $key => $log) {
dd97c328 905 if (!in_array($log->action, $actions)) {
906 continue;
907 }
27bf9e20 908 $info = split(' ', $log->info);
c9f6251e 909
dd97c328 910 if ($info[0] == 'label') { // Labels are ignored in recent activity
c9f6251e 911 continue;
912 }
913
dd97c328 914 if (count($info) != 2) {
915 debugging("Incorrect log entry info: id = ".$log->id, DEBUG_DEVELOPER);
916 continue;
917 }
918
919 $modname = $info[0];
920 $instanceid = $info[1];
921
922 if ($log->action == 'delete mod') {
923 // unfortunately we do not know if the mod was visible
924 if (!array_key_exists($log->info, $newgones)) {
925 $strdeleted = get_string('deletedactivity', 'moodle', get_string('modulename', $modname));
926 $changelist[$log->info] = array ('operation' => 'delete', 'text' => $strdeleted);
927 }
928 } else {
929 if (!isset($modinfo->instances[$modname][$instanceid])) {
930 if ($log->action == 'add mod') {
931 // do not display added and later deleted activities
932 $newgones[$log->info] = true;
933 }
934 continue;
935 }
936 $cm = $modinfo->instances[$modname][$instanceid];
937 if (!$cm->uservisible) {
ff96219d 938 continue;
dd97c328 939 }
940
941 if ($log->action == 'add mod') {
942 $stradded = get_string('added', 'moodle', get_string('modulename', $modname));
943 $changelist[$log->info] = array('operation' => 'add', 'text' => "$stradded:<br /><a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id={$cm->id}\">".format_string($cm->name, true)."</a>");
944
945 } else if ($log->action == 'update mod' and empty($changelist[$log->info])) {
946 $strupdated = get_string('updated', 'moodle', get_string('modulename', $modname));
947 $changelist[$log->info] = array('operation' => 'update', 'text' => "$strupdated:<br /><a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id={$cm->id}\">".format_string($cm->name, true)."</a>");
600149be 948 }
ef25340c 949 }
950 }
951 }
952
9c9f7d77 953 if (!empty($changelist)) {
dd97c328 954 print_headline(get_string('courseupdates').':', 3);
955 $content = true;
ef25340c 956 foreach ($changelist as $changeinfo => $change) {
dd97c328 957 echo '<p class="activity">'.$change['text'].'</p>';
600149be 958 }
89adb174 959 }
bf40f9c1 960
dd97c328 961/// Now display new things from each module
0fd7da81 962
dd97c328 963 $usedmodules = array();
964 foreach($modinfo->cms as $cm) {
965 if (isset($usedmodules[$cm->modname])) {
966 continue;
967 }
968 if (!$cm->uservisible) {
969 continue;
970 }
971 $usedmodules[$cm->modname] = $cm->modname;
972 }
e2a3a0e7 973
dd97c328 974 foreach ($usedmodules as $modname) { // Each module gets it's own logs and prints them
975 if (file_exists($CFG->dirroot.'/mod/'.$modname.'/lib.php')) {
976 include_once($CFG->dirroot.'/mod/'.$modname.'/lib.php');
977 $print_recent_activity = $modname.'_print_recent_activity';
296c6ac2 978 if (function_exists($print_recent_activity)) {
dd97c328 979 // NOTE: original $isteacher (second parameter below) was replaced with $viewfullnames!
980 $content = $print_recent_activity($course, $viewfullnames, $timestart) || $content;
600149be 981 }
296c6ac2 982 } else {
238c0dd9 983 debugging("Missing lib.php in lib/{$modname} - please reinstall files or uninstall the module");
600149be 984 }
985 }
986
987 if (! $content) {
27bf9e20 988 echo '<p class="message">'.get_string('nothingnew').'</p>';
600149be 989 }
600149be 990}
991
cb6fec1f 992/**
993 * For a given course, returns an array of course activity objects
994 * Each item in the array contains he following properties:
995 */
d897cae4 996function get_array_of_activities($courseid) {
d897cae4 997// cm - course module id
998// mod - name of the module (eg forum)
999// section - the number of the section (eg week or topic)
1000// name - the name of the instance
5867bfb5 1001// visible - is the instance visible or not
13534ef7
ML
1002// groupingid - grouping id
1003// groupmembersonly - is this instance visible to group members only
86aa7ccf 1004// extra - contains extra string to include in any link
cb6fec1f 1005 global $CFG, $DB;
82bd6a5e 1006 if(!empty($CFG->enableavailability)) {
1007 require_once($CFG->libdir.'/conditionlib.php');
1008 }
8dddba42 1009
d897cae4 1010 $mod = array();
1011
9fa49e22 1012 if (!$rawmods = get_course_mods($courseid)) {
dd97c328 1013 return $mod; // always return array
d897cae4 1014 }
1015
cb6fec1f 1016 if ($sections = $DB->get_records("course_sections", array("course"=>$courseid), "section ASC")) {
d897cae4 1017 foreach ($sections as $section) {
74666583 1018 if (!empty($section->sequence)) {
d897cae4 1019 $sequence = explode(",", $section->sequence);
1020 foreach ($sequence as $seq) {
7af6281f 1021 if (empty($rawmods[$seq])) {
1022 continue;
1023 }
dd97c328 1024 $mod[$seq]->id = $rawmods[$seq]->instance;
1025 $mod[$seq]->cm = $rawmods[$seq]->id;
1026 $mod[$seq]->mod = $rawmods[$seq]->modname;
1027 $mod[$seq]->section = $section->section;
dd97c328 1028 $mod[$seq]->visible = $rawmods[$seq]->visible;
1029 $mod[$seq]->groupmode = $rawmods[$seq]->groupmode;
1030 $mod[$seq]->groupingid = $rawmods[$seq]->groupingid;
13534ef7 1031 $mod[$seq]->groupmembersonly = $rawmods[$seq]->groupmembersonly;
82bd6a5e 1032 $mod[$seq]->indent = $rawmods[$seq]->indent;
1033 $mod[$seq]->completion = $rawmods[$seq]->completion;
dd97c328 1034 $mod[$seq]->extra = "";
82bd6a5e 1035 if(!empty($CFG->enableavailability)) {
1036 condition_info::fill_availability_conditions($rawmods[$seq]);
1037 $mod[$seq]->availablefrom = $rawmods[$seq]->availablefrom;
1038 $mod[$seq]->availableuntil = $rawmods[$seq]->availableuntil;
1039 $mod[$seq]->showavailability = $rawmods[$seq]->showavailability;
1040 $mod[$seq]->conditionscompletion = $rawmods[$seq]->conditionscompletion;
1041 $mod[$seq]->conditionsgrade = $rawmods[$seq]->conditionsgrade;
1042 }
8dddba42 1043
1044 $modname = $mod[$seq]->mod;
1045 $functionname = $modname."_get_coursemodule_info";
1046
3a37b3f8 1047 if (!file_exists("$CFG->dirroot/mod/$modname/lib.php")) {
1048 continue;
1049 }
1050
8dddba42 1051 include_once("$CFG->dirroot/mod/$modname/lib.php");
1052
1053 if (function_exists($functionname)) {
9d361034 1054 if ($info = $functionname($rawmods[$seq])) {
1055 if (!empty($info->extra)) {
1056 $mod[$seq]->extra = $info->extra;
1057 }
1058 if (!empty($info->icon)) {
1059 $mod[$seq]->icon = $info->icon;
1060 }
1ea543df 1061 if (!empty($info->name)) {
1062 $mod[$seq]->name = urlencode($info->name);
1063 }
c9f6251e 1064 }
1065 }
1ea543df 1066 if (!isset($mod[$seq]->name)) {
a5d424df 1067 $mod[$seq]->name = urlencode($DB->get_field($rawmods[$seq]->modname, "name", array("id"=>$rawmods[$seq]->instance)));
1ea543df 1068 }
d897cae4 1069 }
1070 }
1071 }
1072 }
1073 return $mod;
1074}
1075
1076
dd97c328 1077/**
1078 * Returns reference to full info about modules in course (including visibility).
1079 * Cached and as fast as possible (0 or 1 db query).
65a00c97 1080 * @param $course object or 'reset' string to reset caches, modinfo may be updated in db
dd97c328 1081 * @return mixed courseinfo object or nothing if resetting
1082 */
65a00c97 1083function &get_fast_modinfo(&$course, $userid=0) {
cb6fec1f 1084 global $CFG, $USER, $DB;
82bd6a5e 1085 if(!empty($CFG->enableavailability)) {
1086 require_once($CFG->libdir.'/conditionlib.php');
1087 }
dd97c328 1088
1089 static $cache = array();
1090
1091 if ($course === 'reset') {
1092 $cache = array();
1093 $nothing = null;
1094 return $nothing; // we must return some reference
1095 }
1096
1097 if (empty($userid)) {
1098 $userid = $USER->id;
1099 }
1100
1101 if (array_key_exists($course->id, $cache) and $cache[$course->id]->userid == $userid) {
1102 return $cache[$course->id];
1103 }
1104
1105 if (empty($course->modinfo)) {
1106 // no modinfo yet - load it
1107 rebuild_course_cache($course->id);
cb6fec1f 1108 $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
dd97c328 1109 }
1110
1111 $modinfo = new object();
1112 $modinfo->courseid = $course->id;
1113 $modinfo->userid = $userid;
1114 $modinfo->sections = array();
1115 $modinfo->cms = array();
1116 $modinfo->instances = array();
1117 $modinfo->groups = null; // loaded only when really needed - the only one db query
1118
1119 $info = unserialize($course->modinfo);
1120 if (!is_array($info)) {
1121 // hmm, something is wrong - lets try to fix it
1122 rebuild_course_cache($course->id);
cb6fec1f 1123 $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
dd97c328 1124 $info = unserialize($course->modinfo);
1125 if (!is_array($info)) {
1126 return $modinfo;
1127 }
1128 }
1129
1130 if ($info) {
1131 // detect if upgrade required
1132 $first = reset($info);
1133 if (!isset($first->id)) {
1134 rebuild_course_cache($course->id);
cb6fec1f 1135 $course->modinfo = $DB->get_field('course', 'modinfo', array('id'=>$course->id));
dd97c328 1136 $info = unserialize($course->modinfo);
1137 if (!is_array($info)) {
1138 return $modinfo;
1139 }
1140 }
1141 }
1142
1143 $modlurals = array();
1144
00653161 1145 // If we haven't already preloaded contexts for the course, do it now
1146 preload_course_contexts($course->id);
65bcf17b 1147
dd97c328 1148 foreach ($info as $mod) {
7c3b032e 1149 if (empty($mod->name)) {
1150 // something is wrong here
1151 continue;
1152 }
dd97c328 1153 // reconstruct minimalistic $cm
1154 $cm = new object();
1155 $cm->id = $mod->cm;
1156 $cm->instance = $mod->id;
1157 $cm->course = $course->id;
1158 $cm->modname = $mod->mod;
1159 $cm->name = urldecode($mod->name);
1160 $cm->visible = $mod->visible;
76cbde41 1161 $cm->sectionnum = $mod->section;
dd97c328 1162 $cm->groupmode = $mod->groupmode;
1163 $cm->groupingid = $mod->groupingid;
1164 $cm->groupmembersonly = $mod->groupmembersonly;
82bd6a5e 1165 $cm->indent = $mod->indent;
1166 $cm->completion = $mod->completion;
dd97c328 1167 $cm->extra = isset($mod->extra) ? urldecode($mod->extra) : '';
1168 $cm->icon = isset($mod->icon) ? $mod->icon : '';
1169 $cm->uservisible = true;
82bd6a5e 1170 if(!empty($CFG->enableavailability)) {
1171 // We must have completion information from modinfo. If it's not
1172 // there, cache needs rebuilding
1173 if(!isset($mod->availablefrom)) {
1174 debugging('enableavailability option was changed; rebuilding '.
1175 'cache for course '.$course->id);
1176 rebuild_course_cache($course->id,true);
1177 // Re-enter this routine to do it all properly
1178 return get_fast_modinfo($course,$userid);
1179 }
1180 $cm->availablefrom = $mod->availablefrom;
1181 $cm->availableuntil = $mod->availableuntil;
1182 $cm->showavailability = $mod->showavailability;
1183 $cm->conditionscompletion = $mod->conditionscompletion;
1184 $cm->conditionsgrade = $mod->conditionsgrade;
1185 }
dd97c328 1186
7c3b032e 1187 // preload long names plurals and also check module is installed properly
dd97c328 1188 if (!isset($modlurals[$cm->modname])) {
7c3b032e 1189 if (!file_exists("$CFG->dirroot/mod/$cm->modname/lib.php")) {
1190 continue;
1191 }
dd97c328 1192 $modlurals[$cm->modname] = get_string('modulenameplural', $cm->modname);
1193 }
1194 $cm->modplural = $modlurals[$cm->modname];
00653161 1195 $modcontext = get_context_instance(CONTEXT_MODULE,$cm->id);
1196
82bd6a5e 1197 if(!empty($CFG->enableavailability)) {
1198 // Unfortunately the next call really wants to call
1199 // get_fast_modinfo, but that would be recursive, so we fake up a
1200 // modinfo for it already
1201 if(empty($minimalmodinfo)) {
1202 $minimalmodinfo=new stdClass();
1203 $minimalmodinfo->cms=array();
1204 foreach($info as $mod) {
1205 $minimalcm=new stdClass();
1206 $minimalcm->id=$mod->cm;
1207 $minimalcm->name=urldecode($mod->name);
1208 $minimalmodinfo->cms[$minimalcm->id]=$minimalcm;
1209 }
1210 }
1211
1212 // Get availability information
1213 $ci = new condition_info($cm);
1214 $cm->available=$ci->is_available($cm->availableinfo,true,$userid,
1215 $minimalmodinfo);
1216 } else {
1217 $cm->available=true;
1218 }
00653161 1219 if ((!$cm->visible or !$cm->available) and !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
dd97c328 1220 $cm->uservisible = false;
1221
1222 } else if (!empty($CFG->enablegroupings) and !empty($cm->groupmembersonly)
00653161 1223 and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
dd97c328 1224 if (is_null($modinfo->groups)) {
1225 $modinfo->groups = groups_get_user_groups($course->id, $userid);
1226 }
1227 if (empty($modinfo->groups[$cm->groupingid])) {
1228 $cm->uservisible = false;
1229 }
1230 }
1231
1232 if (!isset($modinfo->instances[$cm->modname])) {
1233 $modinfo->instances[$cm->modname] = array();
1234 }
1235 $modinfo->instances[$cm->modname][$cm->instance] =& $cm;
1236 $modinfo->cms[$cm->id] =& $cm;
1237
1238 // reconstruct sections
76cbde41 1239 if (!isset($modinfo->sections[$cm->sectionnum])) {
1240 $modinfo->sections[$cm->sectionnum] = array();
dd97c328 1241 }
76cbde41 1242 $modinfo->sections[$cm->sectionnum][] = $cm->id;
dd97c328 1243
1244 unset($cm);
1245 }
1246
76cbde41 1247 unset($cache[$course->id]); // prevent potential reference problems when switching users
dd97c328 1248 $cache[$course->id] = $modinfo;
1249
1250 return $cache[$course->id];
1251}
d897cae4 1252
cb6fec1f 1253/**
1254 * Returns a number of useful structures for course displays
1255 */
90845098 1256function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modnamesused) {
82bd6a5e 1257 global $DB,$COURSE;
7468bf01 1258
dd97c328 1259 $mods = array(); // course modules indexed by id
1260 $modnames = array(); // all course module names (except resource!)
1261 $modnamesplural= array(); // all course module names (plural form)
1262 $modnamesused = array(); // course module names used
7468bf01 1263
cb6fec1f 1264 if ($allmods = $DB->get_records("modules")) {
90845098 1265 foreach ($allmods as $mod) {
5867bfb5 1266 if ($mod->visible) {
1267 $modnames[$mod->name] = get_string("modulename", "$mod->name");
1268 $modnamesplural[$mod->name] = get_string("modulenameplural", "$mod->name");
1269 }
90845098 1270 }
91374f3e 1271 asort($modnames, SORT_LOCALE_STRING);
90845098 1272 } else {
ba6018a9 1273 print_error("nomodules", 'debug');
90845098 1274 }
1275
82bd6a5e 1276 $course = ($courseid==$COURSE->id) ? $COURSE : $DB->get_record('course',array('id'=>$courseid));
1277 $modinfo = get_fast_modinfo($course);
1278
1279 if ($rawmods=$modinfo->cms) {
7468bf01 1280 foreach($rawmods as $mod) { // Index the mods
959ae824 1281 if (empty($modnames[$mod->modname])) {
1282 continue;
1283 }
dd97c328 1284 $mods[$mod->id] = $mod;
1285 $mods[$mod->id]->modfullname = $modnames[$mod->modname];
1286 if (!$mod->visible and !has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_COURSE, $courseid))) {
1287 continue;
1288 }
13534ef7
ML
1289 // Check groupings
1290 if (!groups_course_module_visible($mod)) {
1291 continue;
1292 }
dd97c328 1293 $modnamesused[$mod->modname] = $modnames[$mod->modname];
7468bf01 1294 }
c7da6f7a 1295 if ($modnamesused) {
dba21d4a 1296 asort($modnamesused, SORT_LOCALE_STRING);
c7da6f7a 1297 }
7468bf01 1298 }
7468bf01 1299}
1300
9fa49e22 1301
7468bf01 1302function get_all_sections($courseid) {
cb6fec1f 1303 global $DB;
1304 return $DB->get_records("course_sections", array("course"=>"$courseid"), "section",
7d99d695 1305 "section, id, course, summary, sequence, visible");
7468bf01 1306}
1307
b86fc0e2 1308function course_set_display($courseid, $display=0) {
cb6fec1f 1309 global $USER, $DB;
b86fc0e2 1310
b86fc0e2 1311 if ($display == "all" or empty($display)) {
1312 $display = 0;
1313 }
1314
7b678e0a 1315 if (empty($USER->id) or $USER->username == 'guest') {
1316 //do not store settings in db for guests
238c0dd9 1317 } else if ($DB->record_exists("course_display", array("userid" => $USER->id, "course"=>$courseid))) {
cb6fec1f 1318 $DB->set_field("course_display", "display", $display, array("userid"=>$USER->id, "course"=>$courseid));
b86fc0e2 1319 } else {
dd97c328 1320 $record = new object();
b86fc0e2 1321 $record->userid = $USER->id;
1322 $record->course = $courseid;
1323 $record->display = $display;
cb6fec1f 1324 if (!$DB->insert_record("course_display", $record)) {
b86fc0e2 1325 notify("Could not save your course display!");
1326 }
1327 }
1328
1329 return $USER->display[$courseid] = $display; // Note: = not ==
1330}
1331
cb6fec1f 1332/**
1333 * For a given course section, markes it visible or hidden,
1334 * and does the same for every activity in that section
1335 */
7d99d695 1336function set_section_visible($courseid, $sectionnumber, $visibility) {
cb6fec1f 1337 global $DB;
7d99d695 1338
cb6fec1f 1339 if ($section = $DB->get_record("course_sections", array("course"=>$courseid, "section"=>$sectionnumber))) {
1340 $DB->set_field("course_sections", "visible", "$visibility", array("id"=>$section->id));
7d99d695 1341 if (!empty($section->sequence)) {
1342 $modules = explode(",", $section->sequence);
1343 foreach ($modules as $moduleid) {
02f66c42 1344 set_coursemodule_visible($moduleid, $visibility, true);
7d99d695 1345 }
1346 }
5867bfb5 1347 rebuild_course_cache($courseid);
7d99d695 1348 }
1349}
ba2e5d73 1350
cb6fec1f 1351/**
1352 * Prints a section full of activity modules
1353 */
4e781c7b 1354function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false) {
cb6fec1f 1355 global $CFG, $USER, $DB;
7977cffd 1356
dd97c328 1357 static $initialised;
1358
3d575e6f 1359 static $groupbuttons;
32d03b7b 1360 static $groupbuttonslink;
52dcc2f9 1361 static $isediting;
7977cffd 1362 static $ismoving;
1363 static $strmovehere;
1364 static $strmovefull;
54669989 1365 static $strunreadpostsone;
a2d71d8e 1366 static $usetracking;
dd97c328 1367 static $groupings;
4877707e 1368
110a32e2 1369
dd97c328 1370 if (!isset($initialised)) {
9fd9c29b 1371 $groupbuttons = ($course->groupmode or (!$course->groupmodeforce));
32d03b7b 1372 $groupbuttonslink = (!$course->groupmodeforce);
dd97c328 1373 $isediting = isediting($course->id);
1374 $ismoving = $isediting && ismoving($course->id);
3d575e6f 1375 if ($ismoving) {
dd97c328 1376 $strmovehere = get_string("movehere");
1377 $strmovefull = strip_tags(get_string("movefull", "", "'$USER->activitycopyname'"));
3d575e6f 1378 }
94a6a70f 1379 include_once($CFG->dirroot.'/mod/forum/lib.php');
1380 if ($usetracking = forum_tp_can_track_forums()) {
dd97c328 1381 $strunreadpostsone = get_string('unreadpostsone', 'forum');
a2d71d8e 1382 }
dd97c328 1383 $initialised = true;
7977cffd 1384 }
dd97c328 1385
1386 $labelformatoptions = new object();
60bd11cf 1387 $labelformatoptions->noclean = true;
94361e02 1388
fea43a7f 1389/// Casting $course->modinfo to string prevents one notice when the field is null
dd97c328 1390 $modinfo = get_fast_modinfo($course);
238c0dd9 1391
94361e02 1392
c6a55371 1393 //Acccessibility: replace table with list <ul>, but don't output empty list.
74666583 1394 if (!empty($section->sequence)) {
94361e02 1395
f2d660dc 1396 // Fix bug #5027, don't want style=\"width:$width\".
6285f8a8 1397 echo "<ul class=\"section img-text\">\n";
94361e02 1398 $sectionmods = explode(",", $section->sequence);
1399
1400 foreach ($sectionmods as $modnumber) {
9ae687af 1401 if (empty($mods[$modnumber])) {
1402 continue;
1403 }
dd97c328 1404
94361e02 1405 $mod = $mods[$modnumber];
c9f6251e 1406
dd97c328 1407 if ($ismoving and $mod->id == $USER->activitycopy) {
1408 // do not display moving mod
1409 continue;
1410 }
c9f6251e 1411
dd97c328 1412 if (isset($modinfo->cms[$modnumber])) {
85f55ba2 1413 // We can continue (because it will not be displayed at all)
1414 // if:
1415 // 1) The activity is not visible to users
1416 // and
1417 // 2a) The 'showavailability' option is not set (if that is set,
1418 // we need to display the activity so we can show
1419 // availability info)
1420 // or
1421 // 2b) The 'availableinfo' is empty, i.e. the activity was
1422 // hidden in a way that leaves no info, such as using the
1423 // eye icon.
82bd6a5e 1424 if (!$modinfo->cms[$modnumber]->uservisible &&
85f55ba2 1425 (empty($modinfo->cms[$modnumber]->showavailability) ||
1426 empty($modinfo->cms[$modnumber]->availableinfo))) {
dd97c328 1427 // visibility shortcut
1428 continue;
86aa7ccf 1429 }
dd97c328 1430 } else {
0f56c9da 1431 if (!file_exists("$CFG->dirroot/mod/$mod->modname/lib.php")) {
1432 // module not installed
1433 continue;
1434 }
82bd6a5e 1435 if (!coursemodule_visible_for_user($mod) &&
1436 empty($mod->showavailability)) {
dd97c328 1437 // full visibility check
1438 continue;
9d361034 1439 }
dd97c328 1440 }
1441
1442 echo '<li class="activity '.$mod->modname.'" id="module-'.$modnumber.'">'; // Unique ID
1443 if ($ismoving) {
1444 echo '<a title="'.$strmovefull.'"'.
d4a1fcaf 1445 ' href="'.$CFG->wwwroot.'/course/mod.php?moveto='.$mod->id.'&amp;sesskey='.sesskey().'">'.
dd97c328 1446 '<img class="movetarget" src="'.$CFG->pixpath.'/movehere.gif" '.
1447 ' alt="'.$strmovehere.'" /></a><br />
1448 ';
1449 }
9d361034 1450
dd97c328 1451 if ($mod->indent) {
1452 print_spacer(12, 20 * $mod->indent, false);
1453 }
1454
554606c7 1455 $extra = '';
1456 if (!empty($modinfo->cms[$modnumber]->extra)) {
82bd6a5e 1457 $extra = $modinfo->cms[$modnumber]->extra;
554606c7 1458 }
dd97c328 1459
1460 if ($mod->modname == "label") {
82bd6a5e 1461 if (!$mod->visible || !$mod->uservisible) {
85f55ba2 1462 echo '<div class="dimmed_text"><span class="accesshide">'.
4a087123 1463 get_string('hiddenfromstudents').'</span>';
dd97c328 1464 }
1465 echo format_text($extra, FORMAT_HTML, $labelformatoptions);
4a087123 1466 if (!$mod->visible || !$mod->uservisible) {
9009a990 1467 echo "</div>";
aac94fd0 1468 }
c4d989a1 1469 if (!empty($CFG->enablegroupings) && !empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
1470 if (!isset($groupings)) {
1471 $groupings = groups_get_all_groupings($course->id);
1472 }
1470825e 1473 echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
c4d989a1 1474 }
aac94fd0 1475
dd97c328 1476 } else { // Normal activity
1477 $instancename = format_string($modinfo->cms[$modnumber]->name, true, $course->id);
c9f6251e 1478
dd97c328 1479 if (!empty($modinfo->cms[$modnumber]->icon)) {
1480 $icon = "$CFG->pixpath/".$modinfo->cms[$modnumber]->icon;
1481 } else {
1482 $icon = "$CFG->modpixpath/$mod->modname/icon.gif";
1483 }
e0b033d5 1484
dd97c328 1485 //Accessibility: for files get description via icon.
1486 $altname = '';
1487 if ('resource'==$mod->modname) {
1488 if (!empty($modinfo->cms[$modnumber]->icon)) {
1489 $possaltname = $modinfo->cms[$modnumber]->icon;
6285f8a8 1490
dd97c328 1491 $mimetype = mimeinfo_from_icon('type', $possaltname);
1492 $altname = get_mimetype_description($mimetype);
6285f8a8 1493 } else {
1494 $altname = $mod->modfullname;
1495 }
dd97c328 1496 } else {
1497 $altname = $mod->modfullname;
1498 }
1499 // Avoid unnecessary duplication.
1500 if (false!==stripos($instancename, $altname)) {
1501 $altname = '';
1502 }
1503 // File type after name, for alphabetic lists (screen reader).
1504 if ($altname) {
1505 $altname = get_accesshide(' '.$altname);
1506 }
6285f8a8 1507
82bd6a5e 1508 // We may be displaying this just in order to show information
1509 // about visibility, without the actual link
1510 if($mod->uservisible) {
1511 // Display normal module link
85f55ba2 1512 if($mod->visible) {
1513 $linkcss='';
1514 $accesstext='';
1515 } else {
1516 $linkcss = ' class="dimmed" ';
1517 $accesstext='<span class="accesshide">'.
1518 get_string('hiddenfromstudents').': </span>';
1519 }
1520
1521 echo '<a '.$linkcss.' '.$extra.
1522 ' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.
1523 '<img src="'.$icon.'" class="activityicon" alt="" /> '.
1524 $accesstext.'<span>'.$instancename.$altname.'</span></a>';
82bd6a5e 1525
1526 if (!empty($CFG->enablegroupings) && !empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
1527 if (!isset($groupings)) {
1528 $groupings = groups_get_all_groupings($course->id);
1529 }
1530 echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
acf000b0 1531 }
82bd6a5e 1532 } else {
1533 // Display greyed-out text of link
85f55ba2 1534 echo '<span class="dimmed_text" '.$extra.' ><span class="accesshide">'.
1535 get_string('notavailableyet','condition').': </span>'.
1536 '<img src="'.$icon.'" class="activityicon" alt="" /> <span>'.
1537 $instancename.$altname.'</span></span>';
c9f6251e 1538 }
dd97c328 1539 }
1540 if ($usetracking && $mod->modname == 'forum') {
90f4745c 1541 if ($unread = forum_tp_count_forum_unread_posts($mod, $course)) {
1542 echo '<span class="unread"> <a href="'.$CFG->wwwroot.'/mod/forum/view.php?id='.$mod->id.'">';
1543 if ($unread == 1) {
1544 echo $strunreadpostsone;
1545 } else {
1546 print_string('unreadpostsnumber', 'forum', $unread);
54669989 1547 }
90f4745c 1548 echo '</a></span>';
f37da850 1549 }
dd97c328 1550 }
f37da850 1551
dd97c328 1552 if ($isediting) {
1553 // TODO: we must define this as mod property!
1554 if ($groupbuttons and $mod->modname != 'label' and $mod->modname != 'resource' and $mod->modname != 'glossary') {
1555 if (! $mod->groupmodelink = $groupbuttonslink) {
1556 $mod->groupmode = $course->groupmode;
3d575e6f 1557 }
dd97c328 1558
1559 } else {
1560 $mod->groupmode = false;
c9f6251e 1561 }
dd97c328 1562 echo '&nbsp;&nbsp;';
1563 echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
94361e02 1564 }
4e781c7b 1565
1566 // Completion
1567 $completioninfo=new completion_info($course);
1568 $completion=$hidecompletion
1569 ? COMPLETION_TRACKING_NONE
1570 : $completioninfo->is_enabled($mod);
82bd6a5e 1571 if($completion!=COMPLETION_TRACKING_NONE && isloggedin() &&
1572 !isguestuser() && $mod->uservisible) {
4e781c7b 1573 $completiondata=$completioninfo->get_data($mod,true);
1574 $completionicon='';
1575 if($isediting) {
1576 switch($completion) {
ca255392 1577 case COMPLETION_TRACKING_MANUAL :
4e781c7b 1578 $completionicon='manual-enabled'; break;
ca255392 1579 case COMPLETION_TRACKING_AUTOMATIC :
4e781c7b 1580 $completionicon='auto-enabled'; break;
1581 default: // wtf
1582 }
1583 } else if($completion==COMPLETION_TRACKING_MANUAL) {
1584 switch($completiondata->completionstate) {
1585 case COMPLETION_INCOMPLETE:
1586 $completionicon='manual-n'; break;
1587 case COMPLETION_COMPLETE:
1588 $completionicon='manual-y'; break;
1589 }
1590 } else { // Automatic
1591 switch($completiondata->completionstate) {
1592 case COMPLETION_INCOMPLETE:
1593 $completionicon='auto-n'; break;
1594 case COMPLETION_COMPLETE:
1595 $completionicon='auto-y'; break;
1596 case COMPLETION_COMPLETE_PASS:
1597 $completionicon='auto-pass'; break;
1598 case COMPLETION_COMPLETE_FAIL:
1599 $completionicon='auto-fail'; break;
1600 }
1601 }
1602 if($completionicon) {
f17a0360 1603 static $shownhelp=false;
4e781c7b 1604 $imgsrc=$CFG->pixpath.'/i/completion-'.$completionicon.'.gif';
1605 $imgalt=get_string('completion-alt-'.$completionicon,'completion');
1606 if($completion==COMPLETION_TRACKING_MANUAL && !$isediting) {
1607 $imgtitle=get_string('completion-title-'.$completionicon,'completion');
1608 $newstate=
1609 $completiondata->completionstate==COMPLETION_COMPLETE
ca255392 1610 ? COMPLETION_INCOMPLETE
1611 : COMPLETION_COMPLETE;
4e781c7b 1612 // In manual mode the icon is a toggle form.
1613 echo "
f17a0360 1614<form class='togglecompletion' method='post' action='togglecompletion.php'><div>";
5c168a03 1615 if(!$shownhelp && !$isediting) {
f17a0360 1616 helpbutton('completionicons',get_string('completionicons','completion'),'completion');
1617 $shownhelp=true;
1618 }
1619 echo "
4e781c7b 1620<input type='hidden' name='id' value='{$mod->id}' />
1621<input type='hidden' name='completionstate' value='$newstate' />
1622<input type='image' src='$imgsrc' alt='$imgalt' title='$imgtitle' />
1623</div></form>";
1624 } else {
1625 // In auto mode, or when editing, the icon is just an image
f17a0360 1626 echo "<span class='autocompletion'>";
5c168a03 1627 if(!$shownhelp && !$isediting) {
f17a0360 1628 helpbutton('completionicons',get_string('completionicons','completion'),'completion');
1629 $shownhelp=true;
1630 }
1631 echo "<img src='$imgsrc' alt='$imgalt' title='$imgalt' /></span>";
4e781c7b 1632 }
1633 }
1634 }
1635
82bd6a5e 1636 // Show availability information (for someone who isn't allowed to
1637 // see the activity itself, or for staff)
1638 if(!$mod->uservisible) {
1639 echo '<div class="availabilityinfo">'.$mod->availableinfo.'</div>';
1640 } else if($isediting && !empty($CFG->enableavailability)) {
1641 $ci = new condition_info($mod);
1642 $fullinfo=$ci->get_full_information();
1643 if($fullinfo) {
1644 echo '<div class="availabilityinfo">'.get_string($mod->showavailability
1645 ? 'userrestriction_visible'
1646 : 'userrestriction_hidden','condition',
1647 $fullinfo).'</div>';
1648 }
1649 }
1650
dd97c328 1651 echo "</li>\n";
94361e02 1652 }
dd97c328 1653
f2d660dc 1654 } elseif ($ismoving) {
1655 echo "<ul class=\"section\">\n";
264867fd 1656 }
dd97c328 1657
7977cffd 1658 if ($ismoving) {
64fdc686 1659 echo '<li><a title="'.$strmovefull.'"'.
d4a1fcaf 1660 ' href="'.$CFG->wwwroot.'/course/mod.php?movetosection='.$section->id.'&amp;sesskey='.sesskey().'">'.
446390fb 1661 '<img class="movetarget" src="'.$CFG->pixpath.'/movehere.gif" '.
c6a55371 1662 ' alt="'.$strmovehere.'" /></a></li>
1c919752 1663 ';
7977cffd 1664 }
c6a55371 1665 if (!empty($section->sequence) || $ismoving) {
1666 echo "</ul><!--class='section'-->\n\n";
1667 }
a7ad3ea6 1668}
1669
89bfeee0 1670/**
1671 * Prints the menus to add activities and resources.
1672 */
cb57e6f4 1673function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false) {
89bfeee0 1674 global $CFG;
e0161bff 1675
217a8ee9 1676 // check to see if user can add menus
1677 if (!has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $course->id))) {
e2cd3ed0 1678 return false;
217a8ee9 1679 }
1680
89bfeee0 1681 static $resources = false;
1682 static $activities = false;
e0161bff 1683
238c0dd9 1684 if ($resources === false) {
89bfeee0 1685 $resources = array();
1686 $activities = array();
6da4b261 1687
89bfeee0 1688 foreach($modnames as $modname=>$modnamestr) {
1689 if (!course_allowed_module($course, $modname)) {
1690 continue;
1691 }
6da4b261 1692
ffd58dd6 1693 $libfile = "$CFG->dirroot/mod/$modname/lib.php";
1694 if (!file_exists($libfile)) {
1695 continue;
1696 }
1697 include_once($libfile);
89bfeee0 1698 $gettypesfunc = $modname.'_get_types';
1699 if (function_exists($gettypesfunc)) {
1700 $types = $gettypesfunc();
1701 foreach($types as $type) {
65bcf17b 1702 if (!isset($type->modclass) or !isset($type->typestr)) {
ddb0a19f 1703 debugging('Incorrect activity type in '.$modname);
65bcf17b 1704 continue;
1705 }
89bfeee0 1706 if ($type->modclass == MOD_CLASS_RESOURCE) {
1707 $resources[$type->type] = $type->typestr;
1708 } else {
1709 $activities[$type->type] = $type->typestr;
1710 }
1711 }
1712 } else {
1713 // all mods without type are considered activity
1714 $activities[$modname] = $modnamestr;
1715 }
0705ff84 1716 }
e0161bff 1717 }
1718
89bfeee0 1719 $straddactivity = get_string('addactivity');
1720 $straddresource = get_string('addresource');
1721
4f24b3e3 1722 $output = '<div class="section_add_menus">';
1723
1724 if (!$vertical) {
1725 $output .= '<div class="horizontal">';
1726 }
89bfeee0 1727
1728 if (!empty($resources)) {
1729 $output .= popup_form("$CFG->wwwroot/course/mod.php?id=$course->id&amp;section=$section&amp;sesskey=".sesskey()."&amp;add=",
0705ff84 1730 $resources, "ressection$section", "", $straddresource, 'resource/types', $straddresource, true);
1731 }
cb57e6f4 1732
89bfeee0 1733 if (!empty($activities)) {
1734 $output .= ' ';
1735 $output .= popup_form("$CFG->wwwroot/course/mod.php?id=$course->id&amp;section=$section&amp;sesskey=".sesskey()."&amp;add=",
1736 $activities, "section$section", "", $straddactivity, 'mods', $straddactivity, true);
0705ff84 1737 }
1738
4f24b3e3 1739 if (!$vertical) {
d33d0cda 1740 $output .= '</div>';
1741 }
1742
cb57e6f4 1743 $output .= '</div>';
1744
1745 if ($return) {
1746 return $output;
1747 } else {
1748 echo $output;
1749 }
e0161bff 1750}
1751
8ed5dd63 1752/**
1753 * Return the course category context for the category with id $categoryid, except
1754 * that if $categoryid is 0, return the system context.
1755 *
1756 * @param integer $categoryid a category id or 0.
1757 * @return object the corresponding context
1758 */
1759function get_category_or_system_context($categoryid) {
1760 if ($categoryid) {
1761 return get_context_instance(CONTEXT_COURSECAT, $categoryid);
1762 } else {
1763 return get_context_instance(CONTEXT_SYSTEM);
1764 }
1765}
1766
f36cbf1d 1767/**
1768 * Rebuilds the cached list of course activities stored in the database
1769 * @param int $courseid - id of course to rebuil, empty means all
1770 * @param boolean $clearonly - only clear the modinfo fields, gets rebuild automatically on the fly
1771 */
1772function rebuild_course_cache($courseid=0, $clearonly=false) {
f33e1ed4 1773 global $COURSE, $DB;
f36cbf1d 1774
1775 if ($clearonly) {
1c69b885 1776 if (empty($courseid)) {
1777 $courseselect = array();
1778 } else {
1779 $courseselect = array('id'=>$courseid);
1780 }
1781 $DB->set_field('course', 'modinfo', null, $courseselect);
f36cbf1d 1782 // update cached global COURSE too ;-)
1783 if ($courseid == $COURSE->id) {
238c0dd9 1784 $COURSE->modinfo = null;
f36cbf1d 1785 }
1786 // reset the fast modinfo cache
1787 $reset = 'reset';
1788 get_fast_modinfo($reset);
1789 return;
1790 }
5867bfb5 1791
1792 if ($courseid) {
cb6fec1f 1793 $select = array('id'=>$courseid);
5867bfb5 1794 } else {
cb6fec1f 1795 $select = array();
6cf890e3 1796 @set_time_limit(0); // this could take a while! MDL-10954
5867bfb5 1797 }
1798
cb6fec1f 1799 if ($rs = $DB->get_recordset("course", $select,'','id,fullname')) {
1800 foreach ($rs as $course) {
5867bfb5 1801 $modinfo = serialize(get_array_of_activities($course->id));
cb6fec1f 1802 if (!$DB->set_field("course", "modinfo", $modinfo, array("id"=>$course->id))) {
6ba65fa0 1803 notify("Could not cache module information for course '" . format_string($course->fullname) . "'!");
5867bfb5 1804 }
dd97c328 1805 // update cached global COURSE too ;-)
1806 if ($course->id == $COURSE->id) {
238c0dd9 1807 $COURSE->modinfo = $modinfo;
dd97c328 1808 }
5867bfb5 1809 }
cb6fec1f 1810 $rs->close();
5867bfb5 1811 }
dd97c328 1812 // reset the fast modinfo cache
65a00c97 1813 $reset = 'reset';
1814 get_fast_modinfo($reset);
5867bfb5 1815}
1816
cb6fec1f 1817/**
8ed5dd63 1818 * Gets the child categories of a given coures category. Uses a static cache
1819 * to make repeat calls efficient.
1820 *
1821 * @param unknown_type $parentid the id of a course category.
1822 * @return array all the child course categories.
cb6fec1f 1823 */
8ed5dd63 1824function get_child_categories($parentid) {
9bb19e58 1825 static $allcategories = null;
1826
1827 // only fill in this variable the first time
1828 if (null == $allcategories) {
1829 $allcategories = array();
1830
1831 $categories = get_categories();
1832 foreach ($categories as $category) {
1833 if (empty($allcategories[$category->parent])) {
1834 $allcategories[$category->parent] = array();
1835 }
1836 $allcategories[$category->parent][] = $category;
1837 }
1838 }
1839
8ed5dd63 1840 if (empty($allcategories[$parentid])) {
9bb19e58 1841 return array();
1842 } else {
8ed5dd63 1843 return $allcategories[$parentid];
9bb19e58 1844 }
1845}
1846
cb6fec1f 1847/**
8ed5dd63 1848 * This function recursively travels the categories, building up a nice list
1849 * for display. It also makes an array that list all the parents for each
1850 * category.
1851 *
1852 * For example, if you have a tree of categories like:
1853 * Miscellaneous (id = 1)
1854 * Subcategory (id = 2)
1855 * Sub-subcategory (id = 4)
1856 * Other category (id = 3)
1857 * Then after calling this function you will have
1858 * $list = array(1 => 'Miscellaneous', 2 => 'Miscellaneous / Subcategory',
1859 * 4 => 'Miscellaneous / Subcategory / Sub-subcategory',
1860 * 3 => 'Other category');
1861 * $parents = array(2 => array(1), 4 => array(1, 2));
1862 *
1863 * If you specify $requiredcapability, then only categories where the current
1864 * user has that capability will be added to $list, although all categories
1865 * will still be added to $parents, and if you only have $requiredcapability
1866 * in a child category, not the parent, then the child catgegory will still be
1867 * included.
1868 *
1869 * If you specify the option $excluded, then that category, and all its children,
1870 * are omitted from the tree. This is useful when you are doing something like
1871 * moving categories, where you do not want to allow people to move a category
1872 * to be the child of itself.
1873 *
1874 * @param array $list For output, accumulates an array categoryid => full category path name
1875 * @param array $parents For output, accumulates an array categoryid => list of parent category ids.
8a1b1c32 1876 * @param string/array $requiredcapability if given, only categories where the current
1877 * user has this capability will be added to $list. Can also be an array of capabilities,
1878 * in which case they are all required.
8ed5dd63 1879 * @param integer $excludeid Omit this category and its children from the lists built.
1880 * @param object $category Build the tree starting at this category - otherwise starts at the top level.
1881 * @param string $path For internal use, as part of recursive calls.
cb6fec1f 1882 */
8ed5dd63 1883function make_categories_list(&$list, &$parents, $requiredcapability = '',
1884 $excludeid = 0, $category = NULL, $path = "") {
1885
9d866ae0 1886 // initialize the arrays if needed
1887 if (!is_array($list)) {
264867fd 1888 $list = array();
9d866ae0 1889 }
1890 if (!is_array($parents)) {
264867fd 1891 $parents = array();
9d866ae0 1892 }
1893
8ed5dd63 1894 if (empty($category)) {
1895 // Start at the top level.
1896 $category = new stdClass;
1897 $category->id = 0;
1898 } else {
1899 // This is the excluded category, don't include it.
1900 if ($excludeid > 0 && $excludeid == $category->id) {
1901 return;
1902 }
1903
1904 // Update $path.
c2cb4545 1905 if ($path) {
6ba65fa0 1906 $path = $path.' / '.format_string($category->name);
c2cb4545 1907 } else {
6ba65fa0 1908 $path = format_string($category->name);
c2cb4545 1909 }
8ed5dd63 1910
1911 // Add this category to $list, if the permissions check out.
3ce50127 1912 if (empty($requiredcapability)) {
8ed5dd63 1913 $list[$category->id] = $path;
3ce50127 1914
1915 } else {
1916 ensure_context_subobj_present($category, CONTEXT_COURSECAT);
1917 $requiredcapability = (array)$requiredcapability;
1918 if (has_all_capabilities($requiredcapability, $category->context)) {
1919 $list[$category->id] = $path;
1920 }
8ed5dd63 1921 }
c2cb4545 1922 }
1923
8ed5dd63 1924 // Add all the children recursively, while updating the parents array.
1925 if ($categories = get_child_categories($category->id)) {
c2cb4545 1926 foreach ($categories as $cat) {
1927 if (!empty($category->id)) {
3bd4de22 1928 if (isset($parents[$category->id])) {
2832badf 1929 $parents[$cat->id] = $parents[$category->id];
1930 }
c2cb4545 1931 $parents[$cat->id][] = $category->id;
1932 }
8ed5dd63 1933 make_categories_list($list, $parents, $requiredcapability, $excludeid, $cat, $path);
c2cb4545 1934 }
1935 }
1936}
1937
1938
cb6fec1f 1939/**
1940 * Recursive function to print out all the categories in a nice format
1941 * with or without courses included
1942 */
8ed5dd63 1943function print_whole_category_list($category=NULL, $displaylist=NULL, $parentslist=NULL, $depth=-1, $showcourses = true) {
9ff5310a 1944 global $CFG;
e05bcf2f 1945
beeee4d2 1946 // maxcategorydepth == 0 meant no limit
1947 if (!empty($CFG->maxcategorydepth) && $depth >= $CFG->maxcategorydepth) {
e05bcf2f 1948 return;
9ff5310a 1949 }
c2cb4545 1950
1951 if (!$displaylist) {
e92fe848 1952 make_categories_list($displaylist, $parentslist);
c2cb4545 1953 }
1954
1955 if ($category) {
8ed5dd63 1956 if ($category->visible or has_capability('moodle/category:viewhiddencategories', get_context_instance(CONTEXT_SYSTEM))) {
1957 print_category_info($category, $depth, $showcourses);
c2cb4545 1958 } else {
1959 return; // Don't bother printing children of invisible categories
1960 }
89adb174 1961
c2cb4545 1962 } else {
c2cb4545 1963 $category->id = "0";
1964 }
1965
9bb19e58 1966 if ($categories = get_child_categories($category->id)) { // Print all the children recursively
c2cb4545 1967 $countcats = count($categories);
1968 $count = 0;
1969 $first = true;
1970 $last = false;
1971 foreach ($categories as $cat) {
1972 $count++;
1973 if ($count == $countcats) {
1974 $last = true;
1975 }
1976 $up = $first ? false : true;
1977 $down = $last ? false : true;
1978 $first = false;
1979
8ed5dd63 1980 print_whole_category_list($cat, $displaylist, $parentslist, $depth + 1, $showcourses);
c2cb4545 1981 }
1982 }
c2cb4545 1983}
1984
cb6fec1f 1985/**
1986 * This function will return $options array for choose_from_menu, with whitespace to denote nesting.
1987 */
0705ff84 1988function make_categories_options() {
1989 make_categories_list($cats,$parents);
1990 foreach ($cats as $key => $value) {
1991 if (array_key_exists($key,$parents)) {
1992 if ($indent = count($parents[$key])) {
1993 for ($i = 0; $i < $indent; $i++) {
1994 $cats[$key] = '&nbsp;'.$cats[$key];
1995 }
1996 }
1997 }
1998 }
1999 return $cats;
2000}
c2cb4545 2001
cb6fec1f 2002/**
2003 * Prints the category info in indented fashion
2004 * This function is only used by print_whole_category_list() above
2005 */
8ed5dd63 2006function print_category_info($category, $depth, $showcourses = false) {
cb6fec1f 2007 global $CFG, $DB;
b48f834c 2008 static $strallowguests, $strrequireskey, $strsummary;
c2cb4545 2009
b48f834c 2010 if (empty($strsummary)) {
e05bcf2f 2011 $strallowguests = get_string('allowguests');
2012 $strrequireskey = get_string('requireskey');
2013 $strsummary = get_string('summary');
b48f834c 2014 }
ba2e5d73 2015
e05bcf2f 2016 $catlinkcss = $category->visible ? '' : ' class="dimmed" ';
d5f26b07 2017
cb6fec1f 2018 $coursecount = $DB->count_records('course') <= FRONTPAGECOURSELIMIT;
8ed5dd63 2019 if ($showcourses and $coursecount) {
fcf9577a 2020 $catimage = '<img src="'.$CFG->pixpath.'/i/course.gif" alt="" />';
b48f834c 2021 } else {
7b0b5c14 2022 $catimage = "&nbsp;";
8ef9cb56 2023 }
b48f834c 2024
fcf9577a 2025 echo "\n\n".'<table class="categorylist">';
d2b6ba70 2026
7ffcbfe1 2027 $courses = get_courses($category->id, 'c.sortorder ASC', 'c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.password,c.summary,c.guest,c.cost,c.currency');
8ed5dd63 2028 if ($showcourses and $coursecount) {
b48f834c 2029
978abb42 2030 echo '<tr>';
b48f834c 2031
2032 if ($depth) {
2033 $indent = $depth*30;
2034 $rows = count($courses) + 1;
a682f0c2 2035 echo '<td class="category indentation" rowspan="'.$rows.'" valign="top">';
b48f834c 2036 print_spacer(10, $indent);
e05bcf2f 2037 echo '</td>';
b48f834c 2038 }
89adb174 2039
9deaeaa1 2040 echo '<td valign="top" class="category image">'.$catimage.'</td>';
fcf9577a 2041 echo '<td valign="top" class="category name">';
6ba65fa0 2042 echo '<a '.$catlinkcss.' href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'. format_string($category->name).'</a>';
e05bcf2f 2043 echo '</td>';
290130b3 2044 echo '<td class="category info">&nbsp;</td>';
e05bcf2f 2045 echo '</tr>';
b48f834c 2046
beeee4d2 2047 // does the depth exceed maxcategorydepth
2048 // maxcategorydepth == 0 or unset meant no limit
2049
2050 $limit = !(isset($CFG->maxcategorydepth) && ($depth >= $CFG->maxcategorydepth-1));
2051
2052 if ($courses && ($limit || $CFG->maxcategorydepth == 0)) {
c2cb4545 2053 foreach ($courses as $course) {
e05bcf2f 2054 $linkcss = $course->visible ? '' : ' class="dimmed" ';
fcf9577a 2055 echo '<tr><td valign="top">&nbsp;';
2056 echo '</td><td valign="top" class="course name">';
6ba65fa0 2057 echo '<a '.$linkcss.' href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">'. format_string($course->fullname).'</a>';
fcf9577a 2058 echo '</td><td align="right" valign="top" class="course info">';
c2cb4545 2059 if ($course->guest ) {
e05bcf2f 2060 echo '<a title="'.$strallowguests.'" href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">';
fcf9577a 2061 echo '<img alt="'.$strallowguests.'" src="'.$CFG->pixpath.'/i/guest.gif" /></a>';
ebe8ddc1 2062 } else {
fcf9577a 2063 echo '<img alt="" style="width:18px;height:16px;" src="'.$CFG->pixpath.'/spacer.gif" />';
0c656181 2064 }
c2cb4545 2065 if ($course->password) {
e05bcf2f 2066 echo '<a title="'.$strrequireskey.'" href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">';
fcf9577a 2067 echo '<img alt="'.$strrequireskey.'" src="'.$CFG->pixpath.'/i/key.gif" /></a>';
ebe8ddc1 2068 } else {
fcf9577a 2069 echo '<img alt="" style="width:18px;height:16px;" src="'.$CFG->pixpath.'/spacer.gif" />';
b48f834c 2070 }
2071 if ($course->summary) {
e05bcf2f 2072 link_to_popup_window ('/course/info.php?id='.$course->id, 'courseinfo',
fcf9577a 2073 '<img alt="'.$strsummary.'" src="'.$CFG->pixpath.'/i/info.gif" />',
b48f834c 2074 400, 500, $strsummary);
ebe8ddc1 2075 } else {
fcf9577a 2076 echo '<img alt="" style="width:18px;height:16px;" src="'.$CFG->pixpath.'/spacer.gif" />';
0c656181 2077 }
e05bcf2f 2078 echo '</td></tr>';
0c656181 2079 }
ba2e5d73 2080 }
d2b6ba70 2081 } else {
b48f834c 2082
e0140f24 2083 echo '<tr>';
2084
b48f834c 2085 if ($depth) {
2086 $indent = $depth*20;
a682f0c2 2087 echo '<td class="category indentation" valign="top">';
b48f834c 2088 print_spacer(10, $indent);
e05bcf2f 2089 echo '</td>';
d2b6ba70 2090 }
89adb174 2091
fcf9577a 2092 echo '<td valign="top" class="category name">';
6ba65fa0 2093 echo '<a '.$catlinkcss.' href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'. format_string($category->name).'</a>';
e05bcf2f 2094 echo '</td>';
290130b3 2095 echo '<td valign="top" class="category number">';
7ffcbfe1 2096 if (count($courses)) {
2097 echo count($courses);
e05bcf2f 2098 }
2099 echo '</td></tr>';
c2cb4545 2100 }
e05bcf2f 2101 echo '</table>';
c2cb4545 2102}
2103
77eddcd5 2104/**
2105 * Print the buttons relating to course requests.
2106 *
2107 * @param object $systemcontext the system context.
2108 */
2109function print_course_request_buttons($systemcontext) {
2110 global $CFG, $DB;
2111 if (empty($CFG->enablecourserequests)) {
2112 return;
2113 }
e452210a 2114 if (isloggedin() && !isguestuser() && !has_capability('moodle/course:create', $systemcontext) && has_capability('moodle/course:request', $systemcontext)) {
77eddcd5 2115 /// Print a button to request a new course
2116 print_single_button('request.php', NULL, get_string('requestcourse'), 'get');
2117 }
2118 /// Print a button to manage pending requests
2119 if (has_capability('moodle/site:approvecourse', $systemcontext)) {
2120 print_single_button('pending.php', NULL, get_string('coursespending'), 'get', '_self', false, '', !$DB->record_exists('course_request', array()));
2121 }
2122}
2123
8ed5dd63 2124/**
2125 * Prints the turn editing on/off button on course/index.php or course/category.php.
2126 *
2127 * @param integer $categoryid The id of the category we are showing, or 0 for system context.
2128 * @return string HTML of the editing button, or empty string, if this user is not allowed
2129 * to see it.
2130 */
2131function update_category_button($categoryid = 0) {
2132 global $CFG, $USER;
2133
2134 // Check permissions.
2135 $context = get_category_or_system_context($categoryid);
2136 if (!has_any_capability(array('moodle/category:manage', 'moodle/course:create'), $context)) {
2137 return '';
2138 }
2139
2140 // Work out the appropriate action.
2141 if (!empty($USER->categoryediting)) {
2142 $label = get_string('turneditingoff');
2143 $edit = 'off';
2144 } else {
2145 $label = get_string('turneditingon');
2146 $edit = 'on';
2147 }
c2cb4545 2148
8ed5dd63 2149 // Generate the button HTML.
2150 $options = array('categoryedit' => $edit, 'sesskey' => sesskey());
2151 if ($categoryid) {
2152 $options['id'] = $categoryid;
2153 $page = 'category.php';
2154 } else {
2155 $page = 'index.php';
2156 }
2157 return print_single_button($CFG->wwwroot . '/course/' . $page, $options,
2158 $label, 'get', '', true);
2159}
e0b033d5 2160
cb6fec1f 2161/**
2162 * Category is 0 (for all courses) or an object
2163 */
6c54240a 2164function print_courses($category) {
810393c8 2165 global $CFG;
c2cb4545 2166
4dde1463 2167 if (!is_object($category) && $category==0) {
9bb19e58 2168 $categories = get_child_categories(0); // Parent = 0 ie top-level categories only
4dde1463 2169 if (is_array($categories) && count($categories) == 1) {
90c2ca2e 2170 $category = array_shift($categories);
238c0dd9 2171 $courses = get_courses_wmanagers($category->id,
2172 'c.sortorder ASC',
4dde1463 2173 array('password','summary','currency'));
90c2ca2e 2174 } else {
238c0dd9 2175 $courses = get_courses_wmanagers('all',
2176 'c.sortorder ASC',
4dde1463 2177 array('password','summary','currency'));
90c2ca2e 2178 }
2179 unset($categories);
607809b3 2180 } else {
238c0dd9 2181 $courses = get_courses_wmanagers($category->id,
2182 'c.sortorder ASC',
4dde1463 2183 array('password','summary','currency'));
c2cb4545 2184 }
2185
49cd4d79 2186 if ($courses) {
8fee6c60 2187 echo '<ul class="unlist">';
c2cb4545 2188 foreach ($courses as $course) {
4dde1463 2189 if ($course->visible == 1
003bbcc8 2190 || has_capability('moodle/course:viewhiddencourses',$course->context)) {
8fee6c60 2191 echo '<li>';
4dde1463 2192 print_course($course);
8fee6c60 2193 echo "</li>\n";
4dde1463 2194 }
c2cb4545 2195 }
8fee6c60 2196 echo "</ul>\n";
c2cb4545 2197 } else {
f9667a5a 2198 print_heading(get_string("nocoursesyet"));
8e480396 2199 $context = get_context_instance(CONTEXT_SYSTEM);
0468976c 2200 if (has_capability('moodle/course:create', $context)) {
255d1033 2201 $options = array();
2202 $options['category'] = $category->id;
6b7425d2 2203 echo '<div class="addcoursebutton">';
255d1033 2204 print_single_button($CFG->wwwroot.'/course/edit.php', $options, get_string("addnewcourse"));
2205 echo '</div>';
2206 }
c2cb4545 2207 }
c2cb4545 2208}
2209
04c53106 2210/**
2211 * Print a description of a course, suitable for browsing in a list.
2212 *
2213 * @param object $course the course object.
2214 * @param string $highlightterms (optional) some search terms that should be highlighted in the display.
2215 */
2216function print_course($course, $highlightterms = '') {
cb6fec1f 2217 global $CFG, $USER, $DB;
c2cb4545 2218
4dde1463 2219 if (isset($course->context)) {
2220 $context = $course->context;
2221 } else {
2222 $context = get_context_instance(CONTEXT_COURSE, $course->id);
2223 }
146bbb8f 2224
88768091 2225 $linkcss = $course->visible ? '' : ' class="dimmed" ';
22288704 2226
7cd266e9 2227 echo '<div class="coursebox clearfix">';
afba7be1 2228 echo '<div class="info">';
7f9c4fb9 2229 echo '<div class="name"><a title="'.get_string('entercourse').'"'.
e5e81e78 2230 $linkcss.' href="'.$CFG->wwwroot.'/course/view.php?id='.$course->id.'">'.
04c53106 2231 highlight($highlightterms, format_string($course->fullname)).'</a></div>';
238c0dd9 2232
d42c64ba 2233 /// first find all roles that are supposed to be displayed
238c0dd9 2234
6b4d8c4d 2235 if (!empty($CFG->coursemanager)) {
2236 $managerroles = split(',', $CFG->coursemanager);
3bf13d05 2237 $canseehidden = has_capability('moodle/role:viewhiddenassigns', $context);
4dde1463 2238 $namesarray = array();
2239 if (isset($course->managers)) {
2240 if (count($course->managers)) {
2241 $rusers = $course->managers;
2242 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
238c0dd9 2243
b682cee9 2244 /// Rename some of the role names if needed
2245 if (isset($context)) {
cb6fec1f 2246 $aliasnames = $DB->get_records('role_names', array('contextid'=>$context->id), '', 'roleid,contextid,name');
b682cee9 2247 }
2248
9d5a4b23 2249 // keep a note of users displayed to eliminate duplicates
2250 $usersshown = array();
4dde1463 2251 foreach ($rusers as $ra) {
9d5a4b23 2252
2253 // if we've already displayed user don't again
2254 if (in_array($ra->user->id,$usersshown)) {
2255 continue;
2256 }
2257 $usersshown[] = $ra->user->id;
2258
4dde1463 2259 if ($ra->hidden == 0 || $canseehidden) {
238c0dd9 2260 $fullname = fullname($ra->user, $canviewfullnames);
e6924a01 2261 if ($ra->hidden == 1) {
b9837ddf 2262 $status = " <img src=\"{$CFG->pixpath}/t/show.gif\" title=\"".get_string('userhashiddenassignments', 'role')."\" alt=\"".get_string('hiddenassign')."\" class=\"hide-show-image\"/>";
e6924a01 2263 } else {
2264 $status = '';
1780d87b 2265 }
b682cee9 2266
2267 if (isset($aliasnames[$ra->roleid])) {
87486420 2268 $ra->rolename = $aliasnames[$ra->roleid]->name;
b682cee9 2269 }
2270
238c0dd9 2271 $namesarray[] = format_string($ra->rolename)
4dde1463 2272 . ': <a href="'.$CFG->wwwroot.'/user/view.php?id='.$ra->user->id.'&amp;course='.SITEID.'">'
238c0dd9 2273 . $fullname . '</a>' . $status;
4dde1463 2274 }
2275 }
2276 }
2277 } else {
238c0dd9 2278 $rusers = get_role_users($managerroles, $context,
4dde1463 2279 true, '', 'r.sortorder ASC, u.lastname ASC', $canseehidden);
2280 if (is_array($rusers) && count($rusers)) {
2281 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
165d25cc 2282
2283 /// Rename some of the role names if needed
2284 if (isset($context)) {
2285 $aliasnames = $DB->get_records('role_names', array('contextid'=>$context->id), '', 'roleid,contextid,name');
2286 }
2287
4dde1463 2288 foreach ($rusers as $teacher) {
238c0dd9 2289 $fullname = fullname($teacher, $canviewfullnames);
165d25cc 2290
2291 /// Apply role names
2292 if (isset($aliasnames[$teacher->roleid])) {
2293 $teacher->rolename = $aliasnames[$teacher->roleid]->name;
2294 }
2295
238c0dd9 2296 $namesarray[] = format_string($teacher->rolename)
4dde1463 2297 . ': <a href="'.$CFG->wwwroot.'/user/view.php?id='.$teacher->id.'&amp;course='.SITEID.'">'
238c0dd9 2298 . $fullname . '</a>';
4dde1463 2299 }
431cad0d 2300 }
c2cb4545 2301 }
431cad0d 2302
d42c64ba 2303 if (!empty($namesarray)) {
88768091 2304 echo "<ul class=\"teachers\">\n<li>";
2305 echo implode('</li><li>', $namesarray);
2306 echo "</li></ul>";
2307 }
c2cb4545 2308 }
238c0dd9 2309
88768091 2310 require_once("$CFG->dirroot/enrol/enrol.class.php");
2311 $enrol = enrolment_factory::factory($course->enrol);
146bbb8f 2312 echo $enrol->get_access_icons($course);
c2cb4545 2313
afba7be1 2314 echo '</div><div class="summary">';
9f39c190 2315 $options = NULL;
2316 $options->noclean = true;
34b5847a 2317 $options->para = false;
04c53106 2318 echo highlight($highlightterms, format_text($course->summary, FORMAT_MOODLE, $options, $course->id));
afba7be1 2319 echo '</div>';
2320 echo '</div>';
c2cb4545 2321}
2322
cb6fec1f 2323/**
2324 * Prints custom user information on the home page.
2325 * Over time this can include all sorts of information
2326 */
c2cb4545 2327function print_my_moodle() {
cb6fec1f 2328 global $USER, $CFG, $DB;
c2cb4545 2329
86a1ba04 2330 if (empty($USER->id)) {
ba6018a9 2331 print_error('nopermissions', '', '', 'See My Moodle');
c2cb4545 2332 }
2333
5b9e50ca 2334 $courses = get_my_courses($USER->id, 'visible DESC,sortorder ASC', array('summary'));
86dd62a7 2335 $rhosts = array();
2336 $rcourses = array();
36e6379e 2337 if (!empty($CFG->mnet_dispatcher_mode) && $CFG->mnet_dispatcher_mode==='strict') {
86dd62a7 2338 $rcourses = get_my_remotecourses($USER->id);
643b67b8 2339 $rhosts = get_my_remotehosts();
86dd62a7 2340 }
2341
2342 if (!empty($courses) || !empty($rcourses) || !empty($rhosts)) {
2343
2344 if (!empty($courses)) {
8fee6c60 2345 echo '<ul class="unlist">';
86dd62a7 2346 foreach ($courses as $course) {
2347 if ($course->id == SITEID) {
2348 continue;
2349 }
8fee6c60 2350 echo '<li>';
04c53106 2351 print_course($course);
8fee6c60 2352 echo "</li>\n";
86dd62a7 2353 }
8fee6c60 2354 echo "</ul>\n";
86dd62a7 2355 }
2356
2357 // MNET
238c0dd9 2358 if (!empty($rcourses)) {
86dd62a7 2359 // at the IDP, we know of all the remote courses
2360 foreach ($rcourses as $course) {
2361 print_remote_course($course, "100%");
2362 }
2363 } elseif (!empty($rhosts)) {
2364 // non-IDP, we know of all the remote servers, but not courses
2365 foreach ($rhosts as $host) {
643b67b8 2366 print_remote_host($host, "100%");
c81696e5 2367 }
c2cb4545 2368 }
86dd62a7 2369 unset($course);
2370 unset($host);
38a10939 2371
cb6fec1f 2372 if ($DB->count_records("course") > (count($courses) + 1) ) { // Some courses not being displayed
7f989948 2373 echo "<table width=\"100%\"><tr><td align=\"center\">";
2374 print_course_search("", false, "short");
2375 echo "</td><td align=\"center\">";
2376 print_single_button("$CFG->wwwroot/course/index.php", NULL, get_string("fulllistofcourses"), "get");
2377 echo "</td></tr></table>\n";
2378 }
86dd62a7 2379
26330001 2380 } else {
cb6fec1f 2381 if ($DB->count_records("course_categories") > 1) {
cb29b020 2382 print_simple_box_start("center", "100%", "#FFFFFF", 5, "categorybox");
26330001 2383 print_whole_category_list();
2384 print_simple_box_end();
2385 } else {
35d0244a 2386 print_courses(0);
26330001 2387 }
607809b3 2388 }
2b8cef80 2389}
2390
11b0c469 2391
a8b56716 2392function print_course_search($value="", $return=false, $format="plain") {
38a10939 2393 global $CFG;
1e0fb105 2394 static $count = 0;
2395
2396 $count++;
2397
2398 $id = 'coursesearch';
2399
2400 if ($count > 1) {
2401 $id .= $count;
2402 }
38a10939 2403
2404 $strsearchcourses= get_string("searchcourses");
2405
1c919752 2406 if ($format == 'plain') {
1e0fb105 2407 $output = '<form id="'.$id.'" action="'.$CFG->wwwroot.'/course/search.php" method="get">';
fcf9577a 2408 $output .= '<fieldset class="coursesearchbox invisiblefieldset">';
e42f4d92 2409 $output .= '<label for="coursesearchbox">'.$strsearchcourses.': </label>';
cb6fec1f 2410 $output .= '<input type="text" id="coursesearchbox" size="30" name="search" value="'.s($value).'" />';
e42f4d92 2411 $output .= '<input type="submit" value="'.get_string('go').'" />';
fcf9577a 2412 $output .= '</fieldset></form>';
1c919752 2413 } else if ($format == 'short') {
1e0fb105 2414 $output = '<form id="'.$id.'" action="'.$CFG->wwwroot.'/course/search.php" method="get">';
fcf9577a 2415 $output .= '<fieldset class="coursesearchbox invisiblefieldset">';
b1f97418 2416 $output .= '<label for="shortsearchbox">'.$strsearchcourses.': </label>';
cb6fec1f 2417 $output .= '<input type="text" id="shortsearchbox" size="12" name="search" alt="'.s($strsearchcourses).'" value="'.s($value).'" />';
e42f4d92 2418 $output .= '<input type="submit" value="'.get_string('go').'" />';
fcf9577a 2419 $output .= '</fieldset></form>';
1c919752 2420 } else if ($format == 'navbar') {
fcf9577a 2421 $output = '<form id="coursesearchnavbar" action="'.$CFG->wwwroot.'/course/search.php" method="get">';
2422 $output .= '<fieldset class="coursesearchbox invisiblefieldset">';
b1f97418 2423 $output .= '<label for="navsearchbox">'.$strsearchcourses.': </label>';
cb6fec1f 2424 $output .= '<input type="text" id="navsearchbox" size="20" name="search" alt="'.s($strsearchcourses).'" value="'.s($value).'" />';
e42f4d92 2425 $output .= '<input type="submit" value="'.get_string('go').'" />';
fcf9577a 2426 $output .= '</fieldset></form>';
a8b56716 2427 }
2428
2429 if ($return) {
2430 return $output;
2431 }
2432 echo $output;
38a10939 2433}
11b0c469 2434
86dd62a7 2435function print_remote_course($course, $width="100%") {
86dd62a7 2436 global $CFG, $USER;
2437
2438 $linkcss = '';
2439
2440 $url = "{$CFG->wwwroot}/auth/mnet/jump.php?hostid={$course->hostid}&amp;wantsurl=/course/view.php?id={$course->remoteid}";
2441
7cd266e9 2442 echo '<div class="coursebox remotecoursebox clearfix">';
86dd62a7 2443 echo '<div class="info">';
2444 echo '<div class="name"><a title="'.get_string('entercourse').'"'.
2445 $linkcss.' href="'.$url.'">'
6ba65fa0 2446 . format_string($course->fullname) .'</a><br />'
2447 . format_string($course->hostname) . ' : '
238c0dd9 2448 . format_string($course->cat_name) . ' : '
2449 . format_string($course->shortname). '</div>';
86dd62a7 2450 echo '</div><div class="summary">';
2451 $options = NULL;
2452 $options->noclean = true;
2453 $options->para = false;
2454 echo format_text($course->summary, FORMAT_MOODLE, $options);
2455 echo '</div>';
2456 echo '</div>';
86dd62a7 2457}
2458
643b67b8 2459function print_remote_host($host, $width="100%") {
643b67b8 2460 global $CFG, $USER;
2461
2462 $linkcss = '';
2463
7cd266e9 2464 echo '<div class="coursebox clearfix">';
643b67b8 2465 echo '<div class="info">';
2466 echo '<div class="name">';
2467 echo '<img src="'.$CFG->pixpath.'/i/mnethost.gif" class="icon" alt="'.get_string('course').'" />';
2468 echo '<a title="'.s($host['name']).'" href="'.s($host['url']).'">'
2469 . s($host['name']).'</a> - ';
1fd80ad3 2470 echo $host['count'] . ' ' . get_string('courses');
643b67b8 2471 echo '</div>';
2472 echo '</div>';
caa90d56 2473 echo '</div>';
643b67b8 2474}
2475
86dd62a7 2476
11b0c469 2477/// MODULE FUNCTIONS /////////////////////////////////////////////////////////////////
2478
2479function add_course_module($mod) {
cb6fec1f 2480 global $DB;
11b0c469 2481
e5dfd0f3 2482 $mod->added = time();
53f4ad2c 2483 unset($mod->id);
11b0c469 2484
cb6fec1f 2485 return $DB->insert_record("course_modules", $mod);
11b0c469 2486}
2487
97928ddf 2488/**
2489 * Returns course section - creates new if does not exist yet.
2490 * @param int $relative section number
2491 * @param int $courseid
2492 * @return object $course_section object
2493 */
2494function get_course_section($section, $courseid) {
cb6fec1f 2495 global $DB;
2496
2497 if ($cw = $DB->get_record("course_sections", array("section"=>$section, "course"=>$courseid))) {
97928ddf 2498 return $cw;
2499 }
2500 $cw = new object();
cb6fec1f 2501 $cw->course = $courseid;
2502 $cw->section = $section;
2503 $cw->summary = "";
97928ddf 2504 $cw->sequence = "";
cb6fec1f 2505 $id = $DB->insert_record("course_sections", $cw);
dc5af91a 2506 return $DB->get_record("course_sections", array("id"=>$id));
97928ddf 2507}
ece966f0 2508/**
2509 * Given a full mod object with section and course already defined, adds this module to that section.
2510 *
2511 * @param object $mod
2512 * @param int $beforemod An existing ID which we will insert the new module before
2513 * @return int The course_sections ID where the mod is inserted
2514 */
7977cffd 2515function add_mod_to_section($mod, $beforemod=NULL) {
cb6fec1f 2516 global $DB;
11b0c469 2517
cb6fec1f 2518 if ($section = $DB->get_record("course_sections", array("course"=>$mod->course, "section"=>$mod->section))) {
7977cffd 2519
2520 $section->sequence = trim($section->sequence);
2521
2522 if (empty($section->sequence)) {
11b0c469 2523 $newsequence = "$mod->coursemodule";
7977cffd 2524
2525 } else if ($beforemod) {
2526 $modarray = explode(",", $section->sequence);
2527
d857e8b6 2528 if ($key = array_keys($modarray, $beforemod->id)) {
7977cffd 2529 $insertarray = array($mod->id, $beforemod->id);
2530 array_splice($modarray, $key[0], 1, $insertarray);
2531 $newsequence = implode(",", $modarray);
2532
2533 } else { // Just tack it on the end anyway
2534 $newsequence = "$section->sequence,$mod->coursemodule";
2535 }
2536
2537 } else {
2538 $newsequence = "$section->sequence,$mod->coursemodule";
11b0c469 2539 }
89adb174 2540
cb6fec1f 2541 if ($DB->set_field("course_sections", "sequence", $newsequence, array("id"=>$section->id))) {
e5dfd0f3 2542 return $section->id; // Return course_sections ID that was used.
11b0c469 2543 } else {
e5dfd0f3 2544 return 0;
11b0c469 2545 }
89adb174 2546
11b0c469 2547 } else { // Insert a new record
cb6fec1f 2548 $section->course = $mod->course;
2549 $section->section = $mod->section;
2550 $section->summary = "";
e5dfd0f3 2551 $section->sequence = $mod->coursemodule;
cb6fec1f 2552 return $DB->insert_record("course_sections", $section);
11b0c469 2553 }
2554}
2555
48e535bc 2556function set_coursemodule_groupmode($id, $groupmode) {
cb6fec1f 2557 global $DB;
a5d424df 2558 return $DB->set_field("course_modules", "groupmode", $groupmode, array("id"=>$id));
3d575e6f 2559}
2560
177d4abf 2561function set_coursemodule_idnumber($id, $idnumber) {
cb6fec1f 2562 global $DB;
238c0dd9 2563 return $DB->set_field("course_modules", "idnumber", $idnumber, array("id"=>$id));
177d4abf 2564}
4e781c7b 2565
02f66c42 2566/**
2567* $prevstateoverrides = true will set the visibility of the course module
2568* to what is defined in visibleold. This enables us to remember the current
2569* visibility when making a whole section hidden, so that when we toggle
2570* that section back to visible, we are able to return the visibility of
2571* the course module back to what it was originally.
2572*/
2573function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
cb6fec1f 2574 global $DB;
2575 if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
978abb42 2576 return false;
2577 }
cb6fec1f 2578 if (!$modulename = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
978abb42 2579 return false;
2580 }
cb6fec1f 2581 if ($events = $DB->get_records('event', array('instance'=>$cm->instance, 'modulename'=>$modulename))) {
dcd338ff 2582 foreach($events as $event) {
48e535bc 2583 if ($visible) {
2584 show_event($event);
2585 } else {
2586 hide_event($event);
2587 }
dcd338ff 2588 }
2589 }
02f66c42 2590 if ($prevstateoverrides) {
2591 if ($visible == '0') {
2592 // Remember the current visible state so we can toggle this back.
cb6fec1f 2593 $DB->set_field('course_modules', 'visibleold', $cm->visible, array('id'=>$id));
02f66c42 2594 } else {
2595 // Get the previous saved visible states.
cb6fec1f 2596 return $DB->set_field('course_modules', 'visible', $cm->visibleold, array('id'=>$id));
02f66c42 2597 }
2598 }
cb6fec1f 2599 return $DB->set_field("course_modules", "visible", $visible, array("id"=>$id));
1acfbce5 2600}
2601
cb6fec1f 2602/**
290130b3 2603 * Delete a course module and any associated data at the course level (events)
264867fd 2604 * Until 1.5 this function simply marked a deleted flag ... now it
290130b3 2605 * deletes it completely.
2606 *
2607 */
48e535bc 2608function delete_course_module($id) {
cb6fec1f 2609 global $CFG, $DB;
f615fbab 2610 require_once($CFG->libdir.'/gradelib.php');
2611
cb6fec1f 2612 if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
290130b3 2613 return true;
2614 }
cb6fec1f 2615 $modulename = $DB->get_field('modules', 'name', array('id'=>$cm->module));
f615fbab 2616 //delete events from calendar
cb6fec1f 2617 if ($events = $DB->get_records('event', array('instance'=>$cm->instance, 'modulename'=>$modulename))) {
dcd338ff 2618 foreach($events as $event) {
0ea03696 2619 delete_event($event->id);
dcd338ff 2620 }
2621 }
f615fbab 2622 //delete grade items, outcome items and grades attached to modules
2623 if ($grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename,
2624 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course))) {
2625 foreach ($grade_items as $grade_item) {
2626 $grade_item->delete('moddelete');
2627 }
f615fbab 2628 }
06b3a6b2 2629
2630 delete_context(CONTEXT_MODULE, $cm->id);
cb6fec1f 2631 return $DB->delete_records('course_modules', array('id'=>$cm->id));
11b0c469 2632}
2633
2634function delete_mod_from_section($mod, $section) {
cb6fec1f 2635 global $DB;
11b0c469 2636
cb6fec1f 2637 if ($section = $DB->get_record("course_sections", array("id"=>$section)) ) {
11b0c469 2638
e5dfd0f3 2639 $modarray = explode(",", $section->sequence);
11b0c469 2640
2641 if ($key = array_keys ($modarray, $mod)) {
2642 array_splice($modarray, $key[0], 1);
2643 $newsequence = implode(",", $modarray);
cb6fec1f 2644 return $DB->set_field("course_sections", "sequence", $newsequence, array("id"=>$section->id));
11b0c469 2645 } else {
2646 return false;
2647 }
89adb174 2648
11b0c469 2649 }
7977cffd 2650 return false;
11b0c469 2651}
2652
3440ec12 2653/**
2654 * Moves a section up or down by 1. CANNOT BE USED DIRECTLY BY AJAX!
2655 *
2656 * @param object $course
2657 * @param int $section
2658 * @param int $move (-1 or 1)
2659 */
12905134 2660function move_section($course, $section, $move) {
2661/// Moves a whole course section up and down within the course
cb6fec1f 2662 global $USER, $DB;
12905134 2663
2664 if (!$move) {
2665 return true;
2666 }
2667
2668 $sectiondest = $section + $move;
2669
2670 if ($sectiondest > $course->numsections or $sectiondest < 1) {
2671 return false;
2672 }
2673
cb6fec1f 2674 if (!$sectionrecord = $DB->get_record("course_sections", array("course"=>$course->id, "section"=>$section))) {
12905134 2675 return false;
2676 }
2677
cb6fec1f 2678 if (!$sectiondestrecord = $DB->get_record("course_sections", array("course"=>$course->id, "section"=>$sectiondest))) {
12905134 2679 return false;
2680 }
2681
cb6fec1f 2682 if (!$DB->set_field("course_sections", "section", $sectiondest, array("id"=>$sectionrecord->id))) {
12905134 2683 return false;
2684 }
cb6fec1f 2685 if (!$DB->set_field("course_sections", "section", $section, array("id"=>$sectiondestrecord->id))) {
12905134 2686 return false;
2687 }
798b70a1 2688 // if the focus is on the section that is being moved, then move the focus along
2689 if (isset($USER->display[$course->id]) and ($USER->display[$course->id] == $section)) {
2690 course_set_display($course->id, $sectiondest);
2691 }
5390cbb7 2692
a987106d 2693 // Check for duplicates and fix order if needed.
5390cbb7 2694 // There is a very rare case that some sections in the same course have the same section id.
cb6fec1f 2695 $sections = $DB->get_records('course_sections', array('course'=>$course->id), 'section ASC');
a987106d 2696 $n = 0;
2697 foreach ($sections as $section) {
2698 if ($section->section != $n) {
cb6fec1f 2699 if (!$DB->set_field('course_sections', 'section', $n, array('id'=>$section->id))) {
5390cbb7 2700 return false;
2701 }
5390cbb7 2702 }
a987106d 2703 $n++;
5390cbb7 2704 }
12905134 2705 return true;
2706}
2707
3440ec12 2708/**
2709 * Moves a section within a course, from a position to another.
2710 * Be very careful: $section and $destination refer to section number,
2711 * not id!.
2712 *
2713 * @param object $course
2714 * @param int $section Section number (not id!!!)
2715 * @param int $destination
2716 * @return boolean Result
2717 */
2718function move_section_to($course, $section, $destination) {
2719/// Moves a whole course section up and down within the course
2720 global $USER, $DB;
2721
ca255392 2722 if (!$destination && $destination != 0) {
3440ec12 2723 return true;
2724 }
2725
ca255392 2726 if ($destination > $course->numsections) {
3440ec12 2727 return false;
2728 }
2729
2730 // Get all sections for this course and re-order them (2 of them should now share the same section number)
2731 if (!$sections = $DB->get_records_menu('course_sections', array('course' => $course->id),
2732 'section ASC, id ASC', 'id, section')) {
2733 return false;
2734 }
2735
2736 $sections = reorder_sections($sections, $section, $destination);
2737
2738 // Update all sections
2739 foreach ($sections as $id => $position) {
2740 $DB->set_field('course_sections', 'section', $position, array('id' => $id));
2741 }
2742
2743 // if the focus is on the section that is being moved, then move the focus along
2744 if (isset($USER->display[$course->id]) and ($USER->display[$course->id] == $section)) {
2745 course_set_display($course->id, $destination);
2746 }
2747 return true;
2748}
2749
2750/**
2751 * Reordering algorithm for course sections. Given an array of section->section indexed by section->id,
2752 * an original position number and a target position number, rebuilds the array so that the
2753 * move is made without any duplication of section positions.
2754 * Note: The target_position is the position AFTER WHICH the moved section will be inserted. If you want to
2755 * insert a section before the first one, you must give 0 as the target (section 0 can never be moved).
2756 *
2757 * @param array $sections
2758 * @param int $origin_position
2759 * @param int $target_position
2760 * @return array
2761 */
2762function reorder_sections($sections, $origin_position, $target_position) {
2763 if (!is_array($sections)) {
2764 return false;
2765 }
2766
2767 // We can't move section position 0
2768 if ($origin_position < 1) {
2769 echo "We can't move section position 0";
2770 return false;
2771 }
2772
2773 // Locate origin section in sections array
2774 if (!$origin_key = array_search($origin_position, $sections)) {
2775 echo "searched position not in sections array";
2776 return false; // searched position not in sections array
2777 }
2778
2779 // Extract origin section
2780 $origin_section = $sections[$origin_key];
2781 unset($sections[$origin_key]);
2782
2783 // Find offset of target position (stupid PHP's array_splice requires offset instead of key index!)
2784 $found = false;
2785 $append_array = array();
2786 foreach ($sections as $id => $position) {
2787 if ($found) {
2788 $append_array[$id] = $position;
2789 unset($sections[$id]);
2790 }
2791 if ($position == $target_position) {
2792 $found = true;
2793 }
2794 }
2795
2796 // Append moved section
2797 $sections[$origin_key] = $origin_section;
2798
2799 // Append rest of array (if applicable)
2800 if (!empty($append_array)) {
2801 foreach ($append_array as $id => $position) {
2802 $sections[$id] = $position;
2803 }
2804 }
2805
2806 // Renumber positions
2807 $position = 0;
2808 foreach ($sections as $id => $p) {
2809 $sections[$id] = $position;
2810 $position++;
2811 }
2812
2813 return $sections;
2814
2815}
2816
cb6fec1f 2817/**
2818 * Move the module object $mod to the specified $section
2819 * If $beforemod exists then that is the module
2820 * before which $modid should be inserted
2821 * All parameters are objects
2822 */
7977cffd 2823function moveto_module($mod, $section, $beforemod=NULL) {
cb6fec1f 2824 global $DB;
7977cffd 2825
2826/// Remove original module from original section
7977cffd 2827 if (! delete_mod_from_section($mod->id, $mod->section)) {
2828 notify("Could not delete module from existing section");
2829 }
2830
2831/// Update module itself if necessary
2832
2833 if ($mod->section != $section->id) {
89adb174 2834 $mod->section = $section->id;
cb6fec1f 2835 if (!$DB->update_record("course_modules", $mod)) {
7977cffd 2836 return false;
2837 }
48e535bc 2838 // if moving to a hidden section then hide module
2839 if (!$section->visible) {
2840 set_coursemodule_visible($mod->id, 0);
2841 }
7977cffd 2842 }
2843
2844/// Add the module into the new section
2845
2846 $mod->course = $section->course;
2847 $mod->section = $section->section; // need relative reference
2848 $mod->coursemodule = $mod->id;
2849
2850 if (! add_mod_to_section($mod, $beforemod)) {
2851 return false;
2852 }
2853
2854 return true;
7977cffd 2855}
2856
24e1eae4 2857function make_editing_buttons($mod, $absolute=false, $moveselect=true, $indent=-1, $section=-1) {
cb6fec1f 2858 global $CFG, $USER, $DB;
94361e02 2859
3d575e6f 2860 static $str;
37a88449 2861 static $sesskey;
3d575e6f 2862
217a8ee9 2863 $modcontext = get_context_instance(CONTEXT_MODULE, $mod->id);
2864 // no permission to edit
2865 if (!has_capability('moodle/course:manageactivities', $modcontext)) {
e2cd3ed0 2866 return false;
217a8ee9 2867 }
2868
3d575e6f 2869 if (!isset($str)) {
9534a8cb 2870 $str->assign = get_string("assignroles", 'role');
90ebdf65 2871 $str->delete = get_string("delete");
2872 $str->move = get_string("move");
2873 $str->moveup = get_string("moveup");
2874 $str->movedown = get_string("movedown");
2875 $str->moveright = get_string("moveright");
2876 $str->moveleft = get_string("moveleft");
2877 $str->update = get_string("update");
2878 $str->duplicate = get_string("duplicate");
2879 $str->hide = get_string("hide");
2880 $str->show = get_string("show");
3d575e6f 2881 $str->clicktochange = get_string("clicktochange");
32d03b7b 2882 $str->forcedmode = get_string("forcedmode");
3d575e6f 2883 $str->groupsnone = get_string("groupsnone");
2884 $str->groupsseparate = get_string("groupsseparate");
2885 $str->groupsvisible = get_string("groupsvisible");
37a88449 2886 $sesskey = sesskey();
1acfbce5 2887 }
94361e02 2888
24e1eae4 2889 if ($section >= 0) {
75f087b6 2890 $section = '&amp;sr='.$section; // Section return
24e1eae4 2891 } else {
2892 $section = '';
2893 }
2894
94361e02 2895 if ($absolute) {
37a88449 2896 $path = $CFG->wwwroot.'/course';
dc0dc7d5 2897 } else {
37a88449 2898 $path = '.';
dc0dc7d5 2899 }
217a8ee9 2900 if (has_capability('moodle/course:activityvisibility', $modcontext)) {
2901 if ($mod->visible) {
2902 $hideshow = '<a class="editing_hide" title="'.$str->hide.'" href="'.$path.'/mod.php?hide='.$mod->id.
2903 '&amp;sesskey='.$sesskey.$section.'"><img'.
2904 ' src="'.$CFG->pixpath.'/t/hide.gif" class="iconsmall" '.
2905 ' alt="'.$str->hide.'" /></a>'."\n";
2906 } else {
2907 $hideshow = '<a class="editing_show" title="'.$str->show.'" href="'.$path.'/mod.php?show='.$mod->id.
2908 '&amp;sesskey='.$sesskey.$section.'"><img'.
2909 ' src="'.$CFG->pixpath.'/t/show.gif" class="iconsmall" '.
2910 ' alt="'.$str->show.'" /></a>'."\n";
2911 }
530db4cd 2912 } else {
2913 $hideshow = '';
7977cffd 2914 }
530db4cd 2915
3d575e6f 2916 if ($mod->groupmode !== false) {
2917 if ($mod->groupmode == SEPARATEGROUPS) {
32d03b7b 2918 $grouptitle = $str->groupsseparate;
cddbd5d5 2919 $groupclass = 'editing_groupsseparate';
37a88449 2920 $groupimage = $CFG->pixpath.'/t/groups.gif';
2921 $grouplink = $path.'/mod.php?id='.$mod->id.'&amp;groupmode=0&amp;sesskey='.$sesskey;
3d575e6f 2922 } else if ($mod->groupmode == VISIBLEGROUPS) {
32d03b7b 2923 $grouptitle = $str->groupsvisible;
cddbd5d5 2924 $groupclass = 'editing_groupsvisible';
37a88449 2925 $groupimage = $CFG->pixpath.'/t/groupv.gif';
2926 $grouplink = $path.'/mod.php?id='.$mod->id.'&amp;groupmode=1&amp;sesskey='.$sesskey;
32d03b7b 2927 } else {
2928 $grouptitle = $str->groupsnone;
90ebdf65 2929 $groupclass = 'editing_groupsnone';
37a88449 2930 $groupimage = $CFG->pixpath.'/t/groupn.gif';
2931 $grouplink = $path.'/mod.php?id='.$mod->id.'&amp;groupmode=2&amp;sesskey='.$sesskey;
32d03b7b 2932 }
2933 if ($mod->groupmodelink) {
90ebdf65 2934 $groupmode = '<a class="'.$groupclass.'" title="'.$grouptitle.' ('.$str->clicktochange.')" href="'.$grouplink.'">'.
0d905d9f 2935 '<img src="'.$groupimage.'" class="iconsmall" '.
2936 'alt="'.$grouptitle.'" /></a>';
3d575e6f 2937 } else {
37a88449 2938 $groupmode = '<img title="'.$grouptitle.' ('.$str->forcedmode.')" '.
0d905d9f 2939 ' src="'.$groupimage.'" class="iconsmall" '.
2940 'alt="'.$grouptitle.'" />';
3d575e6f 2941 }
2942 } else {
2943 $groupmode = "";
2944 }
e2cd3ed0 2945
217a8ee9 2946 if (has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $mod->course))) {
2947 if ($moveselect) {
2948 $move = '<a class="editing_move" title="'.$str->move.'" href="'.$path.'/mod.php?copy='.$mod->id.
2949 '&amp;sesskey='.$sesskey.$section.'"><img'.
2950 ' src="'.$CFG->pixpath.'/t/move.gif" class="iconsmall" '.
2951 ' alt="'.$str->move.'" /></a>'."\n";
2952 } else {
2953 $move = '<a class="editing_moveup" title="'.$str->moveup.'" href="'.$path.'/mod.php?id='.$mod->id.
2954 '&amp;move=-1&amp;sesskey='.$sesskey.$section.'"><img'.
2955 ' src="'.$CFG->pixpath.'/t/up.gif" class="iconsmall" '.
2956 ' alt="'.$str->moveup.'" /></a>'."\n".
2957 '<a class="editing_movedown" title="'.$str->movedown.'" href="'.$path.'/mod.php?id='.$mod->id.
2958 '&amp;move=1&amp;sesskey='.$sesskey.$section.'"><img'.
2959 ' src="'.$CFG->pixpath.'/t/down.gif" class="iconsmall" '.
2960 ' alt="'.$str->movedown.'" /></a>'."\n";
2961 }
7b44777e 2962 } else {
238c0dd9 2963 $move = '';
7977cffd 2964 }
2965
932be046 2966 $leftright = '';
217a8ee9 2967 if (has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $mod->course))) {
932be046 2968
8047ab1d 2969 if (right_to_left()) { // Exchange arrows on RTL
932be046 2970 $rightarrow = 'left.gif';
2971 $leftarrow = 'right.gif';
2972 } else {
2973 $rightarrow = 'right.gif';
2974 $leftarrow = 'left.gif';
2975 }
238c0dd9 2976
217a8ee9 2977 if ($indent > 0) {
2978 $leftright .= '<a class="editing_moveleft" title="'.$str->moveleft.'" href="'.$path.'/mod.php?id='.$mod->id.
2979 '&amp;indent=-1&amp;sesskey='.$sesskey.$section.'"><img'.
932be046 2980 ' src="'.$CFG->pixpath.'/t/'.$leftarrow.'" class="iconsmall" '.
217a8ee9 2981 ' alt="'.$str->moveleft.'" /></a>'."\n";
2982 }
2983 if ($indent >= 0) {
2984 $leftright .= '<a class="editing_moveright" title="'.$str->moveright.'" href="'.$path.'/mod.php?id='.$mod->id.
2985 '&amp;indent=1&amp;sesskey='.$sesskey.$section.'"><img'.
932be046 2986 ' src="'.$CFG->pixpath.'/t/'.$rightarrow.'" class="iconsmall" '.
217a8ee9 2987 ' alt="'.$str->moveright.'" /></a>'."\n";
2988 }
37a88449 2989 }
9534a8cb 2990 if (has_capability('moodle/course:managegroups', $modcontext)){
2991 $context = get_context_instance(CONTEXT_MODULE, $mod->id);
d1aa1e48 2992 $assign = '<a class="editing_assign" title="'.$str->assign.'" href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.
9534a8cb 2993 $context->id.'"><img src="'.$CFG->pixpath.'/i/roles.gif" alt="'.$str->assign.'" class="iconsmall"/></a>';
8634e001 2994 } else {
2995 $assign = '';
9534a8cb 2996 }
8634e001 2997
90ebdf65 2998 return '<span class="commands">'."\n".$leftright.$move.
2999 '<a class="editing_update" title="'.$str->update.'" href="'.$path.'/mod.php?update='.$mod->id.
37a88449 3000 '&amp;sesskey='.$sesskey.$section.'"><img'.
0d905d9f 3001 ' src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" '.
90ebdf65 3002 ' alt="'.$str->update.'" /></a>'."\n".
3003 '<a class="editing_delete" title="'.$str->delete.'" href="'.$path.'/mod.php?delete='.$mod->id.
37a88449 3004 '&amp;sesskey='.$sesskey.$section.'"><img'.
0d905d9f 3005 ' src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" '.
9534a8cb 3006 ' alt="'.$str->delete.'" /></a>'."\n".$hideshow.$groupmode."\n".$assign.'</span>';
90845098 3007}
3008
b61efafb 3009/**
264867fd 3010 * given a course object with shortname & fullname, this function will
b61efafb 3011 * truncate the the number of chars allowed and add ... if it was too long
3012 */
3013function course_format_name ($course,$max=100) {
264867fd 3014
6ba65fa0 3015 $str = $course->shortname.': '. $course->fullname;
b61efafb 3016 if (strlen($str) <= $max) {
3017 return $str;
3018 }
3019 else {
3020 return substr($str,0,$max-3).'...';
3021 }
3022}
3023
3024/**
3025 * This function will return true if the given course is a child course at all
3026 */
3027function course_in_meta ($course) {
cb6fec1f 3028 global $DB;
3029 return $DB->record_exists("course_meta", array("child_course"=>$course->id));
b61efafb 3030}
3031
48e535bc 3032
3033/**
7cac0c4b 3034 * Print standard form elements on module setup forms in mod/.../mod_form.php
48e535bc 3035 */
263017bb 3036function print_standard_coursemodule_settings($form, $features=null) {
cb6fec1f 3037 global $DB;
3038 if (!$course = $DB->get_record('course', array('id'=>$form->course))) {
ba6018a9 3039 print_error("invalidcourseid");
da2224f8 3040 }
3041 print_groupmode_setting($form, $course);
263017bb 3042 if (!empty($features->groupings)) {
3043 print_grouping_settings($form, $course);
3044 }
da2224f8 3045 print_visible_setting($form, $course);
48e535bc 3046}
3047
3048/**
7cac0c4b 3049 * Print groupmode form element on module setup forms in mod/.../mod_form.php
48e535bc 3050 */
5ebb746b 3051function print_groupmode_setting($form, $course=NULL) {
cb6fec1f 3052 global $DB;
48e535bc 3053
5ebb746b 3054 if (empty($course)) {
cb6fec1f 3055 if (!$course = $DB->get_record('course', array('id'=>$form->course))) {
ba6018a9 3056 print_error("invalidcourseid");
5ebb746b 3057 }
3058 }
48e535bc 3059 if ($form->coursemodule) {
cb6fec1f 3060 if (!$cm = $DB->get_record('course_modules', array('id'=>$form->coursemodule))) {
d857e8b6 3061 print_error('invalidcoursemodule');
48e535bc 3062 }
ffc536af 3063 $groupmode = groups_get_activity_groupmode($cm);
48e535bc 3064 } else {
3065 $cm = null;
ffc536af 3066 $groupmode = groups_get_course_groupmode($course);
48e535bc 3067 }
48e535bc 3068 if ($course->groupmode or (!$course->groupmodeforce)) {
3069 echo '<tr valign="top">';
3070 echo '<td align="right"><b>'.get_string('groupmode').':</b></td>';
7bbe08a2 3071 echo '<td align="left">';
ffc536af 3072 $choices = array();
48e535bc 3073 $choices[NOGROUPS] = get_string('groupsnone');
3074 $choices[SEPARATEGROUPS] = get_string('groupsseparate');
3075 $choices[VISIBLEGROUPS] = get_string('groupsvisible');
3076 choose_from_menu($choices, 'groupmode', $groupmode, '', '', 0, false, $course->groupmodeforce);
3077 helpbutton('groupmode', get_string('groupmode'));
3078 echo '</td></tr>';
3079 }
3080}
3081
263017bb 3082/**
7cac0c4b 3083 * Print groupmode form element on module setup forms in mod/.../mod_form.php
263017bb 3084 */
3085function print_grouping_settings($form, $course=NULL) {
f33e1ed4 3086 global $DB;
263017bb 3087
3088 if (empty($course)) {
cb6fec1f 3089 if (! $course = $DB->get_record('course', array('id'=>$form->course))) {
ba6018a9 3090 print_error("invalidcourseid");
263017bb 3091 }
3092 }
3093 if ($form->coursemodule) {
cb6fec1f 3094 if (!$cm = $DB->get_record('course_modules', array('id'=>$form->coursemodule))) {
d857e8b6 3095 print_error('invalidcoursemodule');
263017bb 3096 }
3097 } else {
3098 $cm = null;
3099 }
3100
f33e1ed4 3101 $groupings = $DB->get_records_menu('groupings', array('courseid'=>$course->id), 'name', 'id, name');
263017bb 3102 if (!empty($groupings)) {
3103 echo '<tr valign="top">';
3104 echo '<td align="right"><b>'.get_string('grouping', 'group').':</b></td>';
3105 echo '<td align="left">';
238c0dd9 3106
263017bb 3107 $groupingid = isset($cm->groupingid) ? $cm->groupingid : 0;
238c0dd9 3108
263017bb 3109 choose_from_menu($groupings, 'groupingid', $groupingid, get_string('none'), '', 0, false);
3110 echo '</td></tr>';
238c0dd9 3111
263017bb 3112 $checked = empty($cm->groupmembersonly) ? '':'checked="checked"';
3113 echo '<tr valign="top">';
3114 echo '<td align="right"><b>'.get_string('groupmembersonly', 'group').':</b></td>';
3115 echo '<td align="left">';
3116 echo "<input type=\"checkbox\" name=\"groupmembersonly\" value=\"1\" $checked />";
3117 echo '</td></tr>';
3118
3119 }
3120}
3121
48e535bc 3122/**
7cac0c4b 3123 * Print visibility setting form element on module setup forms in mod/.../mod_form.php
48e535bc 3124 */
5ebb746b 3125function print_visible_setting($form, $course=NULL) {
cb6fec1f 3126 global $DB;
1ee55c41 3127 if (empty($course)) {
cb6fec1f 3128 if (!$course = $DB->get_record('course', array('id'=>$form->course))) {
ba6018a9 3129 print_error("invalidcourseid");
1ee55c41 3130 }
3131 }
48e535bc 3132 if ($form->coursemodule) {
cb6fec1f 3133 $visible = $DB->get_field('course_modules', 'visible', array('id'=>$form->coursemodule));
48e535bc 3134 } else {
3135 $visible = true;
3136 }
3137
3138 if ($form->mode == 'add') { // in this case $form->section is the section number, not the id
cb6fec1f 3139 $hiddensection = !$DB->get_field('course_sections', 'visible', array('section'=>$form->section, 'course'=>$form->course));
48e535bc 3140 } else {
cb6fec1f 3141 $hiddensection = !$DB->get_field('course_sections', 'visible', array('id'=>$form->section));
48e535bc 3142 }
3143 if ($hiddensection) {
3144 $visible = false;
3145 }
264867fd 3146
48e535bc 3147 echo '<tr valign="top">';
182311e4 3148 echo '<td align="right"><b>'.get_string('visible', '').':</b></td>';
7bbe08a2 3149 echo '<td align="left">';
dd97c328 3150 $choices = array(1 => get_string('show'), 0 => get_string('hide'));
48e535bc 3151 choose_from_menu($choices, 'visible', $visible, '', '', 0, false, $hiddensection);
3152 echo '</td></tr>';
264867fd 3153}
48e535bc 3154
cb6fec1f 3155function update_restricted_mods($course, $mods) {
3156 global $DB;
ddb0a19f 3157
3158/// Delete all the current restricted list
cb6fec1f 3159 $DB->delete_records('course_allowed_modules', array('course'=>$course->id));
ddb0a19f 3160
0705ff84 3161 if (empty($course->restrictmodules)) {