See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Mandatory public API of folder module 20 * 21 * @package mod_folder 22 * @copyright 2009 Petr Skoda {@link http://skodak.org} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** Display folder contents on a separate page */ 29 define('FOLDER_DISPLAY_PAGE', 0); 30 /** Display folder contents inline in a course */ 31 define('FOLDER_DISPLAY_INLINE', 1); 32 33 /** 34 * List of features supported in Folder module 35 * @param string $feature FEATURE_xx constant for requested feature 36 * @return mixed True if module supports feature, false if not, null if doesn't know 37 */ 38 function folder_supports($feature) { 39 switch($feature) { 40 case FEATURE_MOD_ARCHETYPE: return MOD_ARCHETYPE_RESOURCE; 41 case FEATURE_GROUPS: return false; 42 case FEATURE_GROUPINGS: return false; 43 case FEATURE_MOD_INTRO: return true; 44 case FEATURE_COMPLETION_TRACKS_VIEWS: return true; 45 case FEATURE_GRADE_HAS_GRADE: return false; 46 case FEATURE_GRADE_OUTCOMES: return false; 47 case FEATURE_BACKUP_MOODLE2: return true; 48 case FEATURE_SHOW_DESCRIPTION: return true; 49 50 default: return null; 51 } 52 } 53 54 /** 55 * This function is used by the reset_course_userdata function in moodlelib. 56 * @param $data the data submitted from the reset course. 57 * @return array status array 58 */ 59 function folder_reset_userdata($data) { 60 61 // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. 62 // See MDL-9367. 63 64 return array(); 65 } 66 67 /** 68 * List the actions that correspond to a view of this module. 69 * This is used by the participation report. 70 * 71 * Note: This is not used by new logging system. Event with 72 * crud = 'r' and edulevel = LEVEL_PARTICIPATING will 73 * be considered as view action. 74 * 75 * @return array 76 */ 77 function folder_get_view_actions() { 78 return array('view', 'view all'); 79 } 80 81 /** 82 * List the actions that correspond to a post of this module. 83 * This is used by the participation report. 84 * 85 * Note: This is not used by new logging system. Event with 86 * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING 87 * will be considered as post action. 88 * 89 * @return array 90 */ 91 function folder_get_post_actions() { 92 return array('update', 'add'); 93 } 94 95 /** 96 * Add folder instance. 97 * @param object $data 98 * @param object $mform 99 * @return int new folder instance id 100 */ 101 function folder_add_instance($data, $mform) { 102 global $DB; 103 104 $cmid = $data->coursemodule; 105 $draftitemid = $data->files; 106 107 $data->timemodified = time(); 108 // If 'showexpanded' is not set, apply the site config. 109 if (!isset($data->showexpanded)) { 110 $data->showexpanded = get_config('folder', 'showexpanded'); 111 } 112 $data->id = $DB->insert_record('folder', $data); 113 114 // we need to use context now, so we need to make sure all needed info is already in db 115 $DB->set_field('course_modules', 'instance', $data->id, array('id'=>$cmid)); 116 $context = context_module::instance($cmid); 117 118 if ($draftitemid) { 119 file_save_draft_area_files($draftitemid, $context->id, 'mod_folder', 'content', 0, array('subdirs'=>true)); 120 } 121 122 $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; 123 \core_completion\api::update_completion_date_event($data->coursemodule, 'folder', $data->id, $completiontimeexpected); 124 125 return $data->id; 126 } 127 128 /** 129 * Update folder instance. 130 * @param object $data 131 * @param object $mform 132 * @return bool true 133 */ 134 function folder_update_instance($data, $mform) { 135 global $CFG, $DB; 136 137 $cmid = $data->coursemodule; 138 $draftitemid = $data->files; 139 140 $data->timemodified = time(); 141 $data->id = $data->instance; 142 $data->revision++; 143 144 $DB->update_record('folder', $data); 145 146 $context = context_module::instance($cmid); 147 if ($draftitemid = file_get_submitted_draft_itemid('files')) { 148 file_save_draft_area_files($draftitemid, $context->id, 'mod_folder', 'content', 0, array('subdirs'=>true)); 149 } 150 151 $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null; 152 \core_completion\api::update_completion_date_event($data->coursemodule, 'folder', $data->id, $completiontimeexpected); 153 154 return true; 155 } 156 157 /** 158 * Delete folder instance. 159 * @param int $id 160 * @return bool true 161 */ 162 function folder_delete_instance($id) { 163 global $DB; 164 165 if (!$folder = $DB->get_record('folder', array('id'=>$id))) { 166 return false; 167 } 168 169 $cm = get_coursemodule_from_instance('folder', $id); 170 \core_completion\api::update_completion_date_event($cm->id, 'folder', $folder->id, null); 171 172 // note: all context files are deleted automatically 173 174 $DB->delete_records('folder', array('id'=>$folder->id)); 175 176 return true; 177 } 178 179 /** 180 * Lists all browsable file areas 181 * 182 * @package mod_folder 183 * @category files 184 * @param stdClass $course course object 185 * @param stdClass $cm course module object 186 * @param stdClass $context context object 187 * @return array 188 */ 189 function folder_get_file_areas($course, $cm, $context) { 190 $areas = array(); 191 $areas['content'] = get_string('foldercontent', 'folder'); 192 193 return $areas; 194 } 195 196 /** 197 * File browsing support for folder module content area. 198 * 199 * @package mod_folder 200 * @category files 201 * @param file_browser $browser file browser instance 202 * @param array $areas file areas 203 * @param stdClass $course course object 204 * @param stdClass $cm course module object 205 * @param stdClass $context context object 206 * @param string $filearea file area 207 * @param int $itemid item ID 208 * @param string $filepath file path 209 * @param string $filename file name 210 * @return file_info instance or null if not found 211 */ 212 function folder_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { 213 global $CFG; 214 215 216 if ($filearea === 'content') { 217 if (!has_capability('mod/folder:view', $context)) { 218 return NULL; 219 } 220 $fs = get_file_storage(); 221 222 $filepath = is_null($filepath) ? '/' : $filepath; 223 $filename = is_null($filename) ? '.' : $filename; 224 if (!$storedfile = $fs->get_file($context->id, 'mod_folder', 'content', 0, $filepath, $filename)) { 225 if ($filepath === '/' and $filename === '.') { 226 $storedfile = new virtual_root_file($context->id, 'mod_folder', 'content', 0); 227 } else { 228 // not found 229 return null; 230 } 231 } 232 233 require_once("$CFG->dirroot/mod/folder/locallib.php"); 234 $urlbase = $CFG->wwwroot.'/pluginfile.php'; 235 236 // students may read files here 237 $canwrite = has_capability('mod/folder:managefiles', $context); 238 return new folder_content_file_info($browser, $context, $storedfile, $urlbase, $areas[$filearea], true, true, $canwrite, false); 239 } 240 241 // note: folder_intro handled in file_browser automatically 242 243 return null; 244 } 245 246 /** 247 * Serves the folder files. 248 * 249 * @package mod_folder 250 * @category files 251 * @param stdClass $course course object 252 * @param stdClass $cm course module 253 * @param stdClass $context context object 254 * @param string $filearea file area 255 * @param array $args extra arguments 256 * @param bool $forcedownload whether or not force download 257 * @param array $options additional options affecting the file serving 258 * @return bool false if file not found, does not return if found - just send the file 259 */ 260 function folder_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) { 261 global $CFG, $DB; 262 263 if ($context->contextlevel != CONTEXT_MODULE) { 264 return false; 265 } 266 267 require_course_login($course, true, $cm); 268 if (!has_capability('mod/folder:view', $context)) { 269 return false; 270 } 271 272 if ($filearea !== 'content') { 273 // intro is handled automatically in pluginfile.php 274 return false; 275 } 276 277 array_shift($args); // ignore revision - designed to prevent caching problems only 278 279 $fs = get_file_storage(); 280 $relativepath = implode('/', $args); 281 $fullpath = "/$context->id/mod_folder/content/0/$relativepath"; 282 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 283 return false; 284 } 285 286 // finally send the file 287 // for folder module, we force download file all the time 288 send_stored_file($file, 0, 0, true, $options); 289 } 290 291 /** 292 * Return a list of page types 293 * @param string $pagetype current page type 294 * @param stdClass $parentcontext Block's parent context 295 * @param stdClass $currentcontext Current context of block 296 */ 297 function folder_page_type_list($pagetype, $parentcontext, $currentcontext) { 298 $module_pagetype = array('mod-folder-*'=>get_string('page-mod-folder-x', 'folder')); 299 return $module_pagetype; 300 } 301 302 /** 303 * Export folder resource contents 304 * 305 * @return array of file content 306 */ 307 function folder_export_contents($cm, $baseurl) { 308 global $CFG, $DB; 309 $contents = array(); 310 $context = context_module::instance($cm->id); 311 $folder = $DB->get_record('folder', array('id'=>$cm->instance), '*', MUST_EXIST); 312 313 $fs = get_file_storage(); 314 $files = $fs->get_area_files($context->id, 'mod_folder', 'content', 0, 'sortorder DESC, id ASC', false); 315 316 foreach ($files as $fileinfo) { 317 $file = array(); 318 $file['type'] = 'file'; 319 $file['filename'] = $fileinfo->get_filename(); 320 $file['filepath'] = $fileinfo->get_filepath(); 321 $file['filesize'] = $fileinfo->get_filesize(); 322 $file['fileurl'] = file_encode_url("$CFG->wwwroot/" . $baseurl, '/'.$context->id.'/mod_folder/content/'.$folder->revision.$fileinfo->get_filepath().$fileinfo->get_filename(), true); 323 $file['timecreated'] = $fileinfo->get_timecreated(); 324 $file['timemodified'] = $fileinfo->get_timemodified(); 325 $file['sortorder'] = $fileinfo->get_sortorder(); 326 $file['userid'] = $fileinfo->get_userid(); 327 $file['author'] = $fileinfo->get_author(); 328 $file['license'] = $fileinfo->get_license(); 329 $file['mimetype'] = $fileinfo->get_mimetype(); 330 $file['isexternalfile'] = $fileinfo->is_external_file(); 331 if ($file['isexternalfile']) { 332 $file['repositorytype'] = $fileinfo->get_repository_type(); 333 } 334 $contents[] = $file; 335 } 336 337 return $contents; 338 } 339 340 /** 341 * Register the ability to handle drag and drop file uploads 342 * @return array containing details of the files / types the mod can handle 343 */ 344 function folder_dndupload_register() { 345 return array('files' => array( 346 array('extension' => 'zip', 'message' => get_string('dnduploadmakefolder', 'mod_folder')) 347 )); 348 } 349 350 /** 351 * Handle a file that has been uploaded 352 * @param object $uploadinfo details of the file / content that has been uploaded 353 * @return int instance id of the newly created mod 354 */ 355 function folder_dndupload_handle($uploadinfo) { 356 global $DB, $USER; 357 358 // Gather the required info. 359 $data = new stdClass(); 360 $data->course = $uploadinfo->course->id; 361 $data->name = $uploadinfo->displayname; 362 $data->intro = '<p>'.$uploadinfo->displayname.'</p>'; 363 $data->introformat = FORMAT_HTML; 364 $data->coursemodule = $uploadinfo->coursemodule; 365 $data->files = null; // We will unzip the file and sort out the contents below. 366 367 $data->id = folder_add_instance($data, null); 368 369 // Retrieve the file from the draft file area. 370 $context = context_module::instance($uploadinfo->coursemodule); 371 file_save_draft_area_files($uploadinfo->draftitemid, $context->id, 'mod_folder', 'temp', 0, array('subdirs'=>true)); 372 $fs = get_file_storage(); 373 $files = $fs->get_area_files($context->id, 'mod_folder', 'temp', 0, 'sortorder', false); 374 // Only ever one file - extract the contents. 375 $file = reset($files); 376 377 $success = $file->extract_to_storage(new zip_packer(), $context->id, 'mod_folder', 'content', 0, '/', $USER->id); 378 $fs->delete_area_files($context->id, 'mod_folder', 'temp', 0); 379 380 if ($success) { 381 return $data->id; 382 } 383 384 $DB->delete_records('folder', array('id' => $data->id)); 385 return false; 386 } 387 388 /** 389 * Given a coursemodule object, this function returns the extra 390 * information needed to print this activity in various places. 391 * 392 * If folder needs to be displayed inline we store additional information 393 * in customdata, so functions {@link folder_cm_info_dynamic()} and 394 * {@link folder_cm_info_view()} do not need to do DB queries 395 * 396 * @param cm_info $cm 397 * @return cached_cm_info info 398 */ 399 function folder_get_coursemodule_info($cm) { 400 global $DB; 401 if (!($folder = $DB->get_record('folder', array('id' => $cm->instance), 402 'id, name, display, showexpanded, showdownloadfolder, intro, introformat'))) { 403 return NULL; 404 } 405 $cminfo = new cached_cm_info(); 406 $cminfo->name = $folder->name; 407 if ($folder->display == FOLDER_DISPLAY_INLINE) { 408 // prepare folder object to store in customdata 409 $fdata = new stdClass(); 410 $fdata->showexpanded = $folder->showexpanded; 411 $fdata->showdownloadfolder = $folder->showdownloadfolder; 412 if ($cm->showdescription && strlen(trim($folder->intro))) { 413 $fdata->intro = $folder->intro; 414 if ($folder->introformat != FORMAT_MOODLE) { 415 $fdata->introformat = $folder->introformat; 416 } 417 } 418 $cminfo->customdata = $fdata; 419 } else { 420 if ($cm->showdescription) { 421 // Convert intro to html. Do not filter cached version, filters run at display time. 422 $cminfo->content = format_module_intro('folder', $folder, $cm->id, false); 423 } 424 } 425 return $cminfo; 426 } 427 428 /** 429 * Sets dynamic information about a course module 430 * 431 * This function is called from cm_info when displaying the module 432 * mod_folder can be displayed inline on course page and therefore have no course link 433 * 434 * @param cm_info $cm 435 */ 436 function folder_cm_info_dynamic(cm_info $cm) { 437 if ($cm->customdata) { 438 // the field 'customdata' is not empty IF AND ONLY IF we display contens inline 439 $cm->set_no_view_link(); 440 } 441 } 442 443 /** 444 * Overwrites the content in the course-module object with the folder files list 445 * if folder.display == FOLDER_DISPLAY_INLINE 446 * 447 * @param cm_info $cm 448 */ 449 function folder_cm_info_view(cm_info $cm) { 450 global $PAGE; 451 if ($cm->uservisible && $cm->customdata && 452 has_capability('mod/folder:view', $cm->context)) { 453 // Restore folder object from customdata. 454 // Note the field 'customdata' is not empty IF AND ONLY IF we display contens inline. 455 // Otherwise the content is default. 456 $folder = $cm->customdata; 457 $folder->id = (int)$cm->instance; 458 $folder->course = (int)$cm->course; 459 $folder->display = FOLDER_DISPLAY_INLINE; 460 $folder->name = $cm->name; 461 if (empty($folder->intro)) { 462 $folder->intro = ''; 463 } 464 if (empty($folder->introformat)) { 465 $folder->introformat = FORMAT_MOODLE; 466 } 467 // display folder 468 $renderer = $PAGE->get_renderer('mod_folder'); 469 $cm->set_content($renderer->display_folder($folder), true); 470 } 471 } 472 473 /** 474 * Mark the activity completed (if required) and trigger the course_module_viewed event. 475 * 476 * @param stdClass $folder folder object 477 * @param stdClass $course course object 478 * @param stdClass $cm course module object 479 * @param stdClass $context context object 480 * @since Moodle 3.0 481 */ 482 function folder_view($folder, $course, $cm, $context) { 483 484 // Trigger course_module_viewed event. 485 $params = array( 486 'context' => $context, 487 'objectid' => $folder->id 488 ); 489 490 $event = \mod_folder\event\course_module_viewed::create($params); 491 $event->add_record_snapshot('course_modules', $cm); 492 $event->add_record_snapshot('course', $course); 493 $event->add_record_snapshot('folder', $folder); 494 $event->trigger(); 495 496 // Completion. 497 $completion = new completion_info($course); 498 $completion->set_module_viewed($cm); 499 } 500 501 /** 502 * Check if the folder can be zipped and downloaded. 503 * @param stdClass $folder 504 * @param context_module $cm 505 * @return bool True if the folder can be zipped and downloaded. 506 * @throws \dml_exception 507 */ 508 function folder_archive_available($folder, $cm) { 509 if (!$folder->showdownloadfolder) { 510 return false; 511 } 512 513 $context = context_module::instance($cm->id); 514 $fs = get_file_storage(); 515 $dir = $fs->get_area_tree($context->id, 'mod_folder', 'content', 0); 516 517 $size = folder_get_directory_size($dir); 518 $maxsize = get_config('folder', 'maxsizetodownload') * 1024 * 1024; 519 520 if ($size == 0) { 521 return false; 522 } 523 524 if (!empty($maxsize) && $size > $maxsize) { 525 return false; 526 } 527 528 return true; 529 } 530 531 /** 532 * Recursively measure the size of the files in a directory. 533 * @param array $directory 534 * @return int size of directory contents in bytes 535 */ 536 function folder_get_directory_size($directory) { 537 $size = 0; 538 539 foreach ($directory['files'] as $file) { 540 $size += $file->get_filesize(); 541 } 542 543 foreach ($directory['subdirs'] as $subdirectory) { 544 $size += folder_get_directory_size($subdirectory); 545 } 546 547 return $size; 548 } 549 550 /** 551 * Mark the activity completed (if required) and trigger the all_files_downloaded event. 552 * 553 * @param stdClass $folder folder object 554 * @param stdClass $course course object 555 * @param stdClass $cm course module object 556 * @param stdClass $context context object 557 * @since Moodle 3.1 558 */ 559 function folder_downloaded($folder, $course, $cm, $context) { 560 $params = array( 561 'context' => $context, 562 'objectid' => $folder->id 563 ); 564 $event = \mod_folder\event\all_files_downloaded::create($params); 565 $event->add_record_snapshot('course_modules', $cm); 566 $event->add_record_snapshot('course', $course); 567 $event->add_record_snapshot('folder', $folder); 568 $event->trigger(); 569 570 // Completion. 571 $completion = new completion_info($course); 572 $completion->set_module_viewed($cm); 573 } 574 575 /** 576 * Returns all uploads since a given time in specified folder. 577 * 578 * @param array $activities 579 * @param int $index 580 * @param int $timestart 581 * @param int $courseid 582 * @param int $cmid 583 * @param int $userid 584 * @param int $groupid not used, but required for compatibilty with other modules 585 */ 586 function folder_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid=0, $groupid=0) { 587 global $COURSE, $DB, $OUTPUT; 588 589 if ($COURSE->id == $courseid) { 590 $course = $COURSE; 591 } else { 592 $course = $DB->get_record('course', array('id' => $courseid)); 593 } 594 595 $modinfo = get_fast_modinfo($course); 596 $cm = $modinfo->cms[$cmid]; 597 598 $context = context_module::instance($cm->id); 599 if (!has_capability('mod/folder:view', $context)) { 600 return; 601 } 602 $files = folder_get_recent_activity($context, $timestart, $userid); 603 604 foreach ($files as $file) { 605 $tmpactivity = new stdClass(); 606 607 $tmpactivity->type = 'folder'; 608 $tmpactivity->cmid = $cm->id; 609 $tmpactivity->sectionnum = $cm->sectionnum; 610 $tmpactivity->timestamp = $file->get_timemodified(); 611 $tmpactivity->user = core_user::get_user($file->get_userid()); 612 613 $tmpactivity->content = new stdClass(); 614 $tmpactivity->content->url = moodle_url::make_pluginfile_url($file->get_contextid(), 'mod_folder', 'content', 615 $file->get_itemid(), $file->get_filepath(), $file->get_filename()); 616 617 if (file_extension_in_typegroup($file->get_filename(), 'web_image')) { 618 $image = $tmpactivity->content->url->out(false, array('preview' => 'tinyicon', 'oid' => $file->get_timemodified())); 619 $image = html_writer::empty_tag('img', array('src' => $image)); 620 } else { 621 $image = $OUTPUT->pix_icon(file_file_icon($file, 24), $file->get_filename(), 'moodle'); 622 } 623 624 $tmpactivity->content->image = $image; 625 $tmpactivity->content->filename = $file->get_filename(); 626 627 $activities[$index++] = $tmpactivity; 628 } 629 630 } 631 632 /** 633 * Outputs the folder uploads indicated by $activity. 634 * 635 * @param object $activity the activity object the folder resides in 636 * @param int $courseid the id of the course the folder resides in 637 * @param bool $detail not used, but required for compatibilty with other modules 638 * @param int $modnames not used, but required for compatibilty with other modules 639 * @param bool $viewfullnames not used, but required for compatibilty with other modules 640 */ 641 function folder_print_recent_mod_activity($activity, $courseid, $detail, $modnames, $viewfullnames) { 642 global $OUTPUT; 643 644 $content = $activity->content; 645 $tableoptions = [ 646 'border' => '0', 647 'cellpadding' => '3', 648 'cellspacing' => '0' 649 ]; 650 $output = html_writer::start_tag('table', $tableoptions); 651 $output .= html_writer::start_tag('tr'); 652 $output .= html_writer::tag('td', $content->image, ['class' => 'fp-icon', 'valign' => 'top']); 653 $output .= html_writer::start_tag('td'); 654 $output .= html_writer::start_div('fp-filename'); 655 $output .= html_writer::link($content->url, $content->filename); 656 $output .= html_writer::end_div(); 657 658 // Show the uploader. 659 $fullname = fullname($activity->user, $viewfullnames); 660 $userurl = new moodle_url('/user/view.php'); 661 $userurl->params(['id' => $activity->user->id, 'course' => $courseid]); 662 $by = new stdClass(); 663 $by->name = html_writer::link($userurl, $fullname); 664 $by->date = userdate($activity->timestamp); 665 $authornamedate = get_string('bynameondate', 'folder', $by); 666 $output .= html_writer::div($authornamedate, 'user'); 667 668 // Finish up the table. 669 $output .= html_writer::end_tag('tr'); 670 $output .= html_writer::end_tag('table'); 671 672 echo $output; 673 } 674 675 /** 676 * Gets recent file uploads in a given folder. Does not perform security checks. 677 * 678 * @param object $context 679 * @param int $timestart 680 * @param int $userid 681 * 682 * @return array 683 */ 684 function folder_get_recent_activity($context, $timestart, $userid=0) { 685 $newfiles = array(); 686 $fs = get_file_storage(); 687 $files = $fs->get_area_files($context->id, 'mod_folder', 'content'); 688 foreach ($files as $file) { 689 if ($file->get_timemodified() <= $timestart) { 690 continue; 691 } 692 if ($file->get_filename() === '.') { 693 continue; 694 } 695 if (!empty($userid) && $userid !== $file->get_userid()) { 696 continue; 697 } 698 $newfiles[] = $file; 699 } 700 return $newfiles; 701 } 702 703 /** 704 * Given a course and a date, prints a summary of all the new 705 * files posted in folder resources since that date 706 * 707 * @uses CONTEXT_MODULE 708 * @param object $course 709 * @param bool $viewfullnames capability 710 * @param int $timestart 711 * @return bool success 712 */ 713 function folder_print_recent_activity($course, $viewfullnames, $timestart) { 714 global $OUTPUT; 715 716 $folders = get_all_instances_in_course('folder', $course); 717 718 if (empty($folders)) { 719 return false; 720 } 721 722 $newfiles = array(); 723 724 $modinfo = get_fast_modinfo($course); 725 foreach ($folders as $folder) { 726 // Skip resources if the user can't view them. 727 $cm = $modinfo->cms[$folder->coursemodule]; 728 $context = context_module::instance($cm->id); 729 if (!has_capability('mod/folder:view', $context)) { 730 continue; 731 } 732 733 // Get the files uploaded in the current time frame. 734 $newfiles = array_merge($newfiles, folder_get_recent_activity($context, $timestart)); 735 } 736 737 if (empty($newfiles)) { 738 return false; 739 } 740 741 // Build list of files. 742 echo $OUTPUT->heading(get_string('newfoldercontent', 'folder') . ':', 6); 743 $list = html_writer::start_tag('ul', ['class' => 'unlist']); 744 foreach ($newfiles as $file) { 745 $filename = $file->get_filename(); 746 $url = moodle_url::make_pluginfile_url($file->get_contextid(), 'mod_folder', 'content', 747 $file->get_itemid(), $file->get_filepath(), $filename); 748 749 $list .= html_writer::start_tag('li'); 750 $list .= html_writer::start_div('head'); 751 $list .= html_writer::div(userdate($file->get_timemodified(), get_string('strftimerecent')), 'date'); 752 $list .= html_writer::div($file->get_author(), 'name'); 753 $list .= html_writer::end_div(); // Head. 754 755 $list .= html_writer::start_div('info'); 756 $list .= html_writer::link($url, $filename); 757 $list .= html_writer::end_div(); // Info. 758 $list .= html_writer::end_tag('li'); 759 } 760 $list .= html_writer::end_tag('ul'); 761 echo $list; 762 return true; 763 } 764 765 /** 766 * Check if the module has any update that affects the current user since a given time. 767 * 768 * @param cm_info $cm course module data 769 * @param int $from the time to check updates from 770 * @param array $filter if we need to check only specific updates 771 * @return stdClass an object with the different type of areas indicating if they were updated or not 772 * @since Moodle 3.2 773 */ 774 function folder_check_updates_since(cm_info $cm, $from, $filter = array()) { 775 $updates = course_check_module_updates_since($cm, $from, array('content'), $filter); 776 return $updates; 777 } 778 779 /** 780 * This function receives a calendar event and returns the action associated with it, or null if there is none. 781 * 782 * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event 783 * is not displayed on the block. 784 * 785 * @param calendar_event $event 786 * @param \core_calendar\action_factory $factory 787 * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default). 788 * @return \core_calendar\local\event\entities\action_interface|null 789 */ 790 function mod_folder_core_calendar_provide_event_action(calendar_event $event, 791 \core_calendar\action_factory $factory, 792 int $userid = 0) { 793 global $USER; 794 795 if (!$userid) { 796 $userid = $USER->id; 797 } 798 799 $cm = get_fast_modinfo($event->courseid, $userid)->instances['folder'][$event->instance]; 800 801 if (!$cm->uservisible) { 802 // The module is not visible to the user for any reason. 803 return null; 804 } 805 806 $completion = new \completion_info($cm->get_course()); 807 808 $completiondata = $completion->get_data($cm, false, $userid); 809 810 if ($completiondata->completionstate != COMPLETION_INCOMPLETE) { 811 return null; 812 } 813 814 return $factory->create_instance( 815 get_string('view'), 816 new \moodle_url('/mod/folder/view.php', ['id' => $cm->id]), 817 1, 818 true 819 ); 820 } 821 822 /** 823 * Given an array with a file path, it returns the itemid and the filepath for the defined filearea. 824 * 825 * @param string $filearea The filearea. 826 * @param array $args The path (the part after the filearea and before the filename). 827 * @return array The itemid and the filepath inside the $args path, for the defined filearea. 828 */ 829 function mod_folder_get_path_from_pluginfile(string $filearea, array $args) : array { 830 // Folder never has an itemid (the number represents the revision but it's not stored in database). 831 array_shift($args); 832 833 // Get the filepath. 834 if (empty($args)) { 835 $filepath = '/'; 836 } else { 837 $filepath = '/' . implode('/', $args) . '/'; 838 } 839 840 return [ 841 'itemid' => 0, 842 'filepath' => $filepath, 843 ]; 844 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body