Proyectos de Subversion Moodle

Rev

Rev 11 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 11 Rev 1441
Línea 27... Línea 27...
27
use core\di;
27
use core\di;
28
use core\hook;
28
use core\hook;
29
use core_course\external\course_summary_exporter;
29
use core_course\external\course_summary_exporter;
30
use core_courseformat\base as course_format;
30
use core_courseformat\base as course_format;
31
use core_courseformat\formatactions;
31
use core_courseformat\formatactions;
-
 
32
use core_courseformat\sectiondelegate;
32
use core\output\local\action_menu\subpanel as action_menu_subpanel;
33
use core\output\local\action_menu\subpanel as action_menu_subpanel;
Línea 33... Línea 34...
33
 
34
 
34
require_once($CFG->libdir.'/completionlib.php');
35
require_once($CFG->libdir.'/completionlib.php');
35
require_once($CFG->libdir.'/filelib.php');
36
require_once($CFG->libdir.'/filelib.php');
Línea 478... Línea 479...
478
        return context_system::instance();
479
        return context_system::instance();
479
    }
480
    }
480
}
481
}
Línea 481... Línea 482...
481
 
482
 
482
/**
-
 
483
 * Print the buttons relating to course requests.
-
 
484
 *
-
 
485
 * @param context $context current page context.
-
 
486
 * @deprecated since Moodle 4.0
-
 
487
 * @todo Final deprecation MDL-73976
-
 
488
 */
-
 
489
function print_course_request_buttons($context) {
-
 
490
    global $CFG, $DB, $OUTPUT;
-
 
491
    debugging("print_course_request_buttons() is deprecated. " .
-
 
492
        "This is replaced with the category_action_bar tertiary navigation.", DEBUG_DEVELOPER);
-
 
493
    if (empty($CFG->enablecourserequests)) {
-
 
494
        return;
-
 
495
    }
-
 
496
    if (course_request::can_request($context)) {
-
 
497
        // Print a button to request a new course.
-
 
498
        $params = [];
-
 
499
        if ($context instanceof context_coursecat) {
-
 
500
            $params['category'] = $context->instanceid;
-
 
501
        }
-
 
502
        echo $OUTPUT->single_button(new moodle_url('/course/request.php', $params),
-
 
503
            get_string('requestcourse'), 'get');
-
 
504
    }
-
 
505
    /// Print a button to manage pending requests
-
 
506
    if (has_capability('moodle/site:approvecourse', $context)) {
-
 
507
        $disabled = !$DB->record_exists('course_request', array());
-
 
508
        echo $OUTPUT->single_button(new moodle_url('/course/pending.php'), get_string('coursespending'), 'get', array('disabled' => $disabled));
-
 
509
    }
-
 
510
}
-
 
511
 
-
 
512
/**
483
/**
513
 * Does the user have permission to edit things in this category?
484
 * Does the user have permission to edit things in this category?
514
 *
485
 *
515
 * @param integer $categoryid The id of the category we are showing, or 0 for system context.
486
 * @param integer $categoryid The id of the category we are showing, or 0 for system context.
516
 * @return boolean has_any_capability(array(...), ...); in the appropriate context.
487
 * @return boolean has_any_capability(array(...), ...); in the appropriate context.
Línea 575... Línea 546...
575
 * @param int $sectionnum relative number of the section (field course_sections.section)
546
 * @param int $sectionnum relative number of the section (field course_sections.section)
576
 *     If section does not exist it will be created
547
 *     If section does not exist it will be created
577
 * @param int|stdClass $beforemod id or object with field id corresponding to the module
548
 * @param int|stdClass $beforemod id or object with field id corresponding to the module
578
 *     before which the module needs to be included. Null for inserting in the
549
 *     before which the module needs to be included. Null for inserting in the
579
 *     end of the section
550
 *     end of the section
-
 
551
 * @param string $modname Optional, name of the module in the modules table. We need to do some checks
-
 
552
 *      to see if this module type can be displayed to the course page.
-
 
553
 *      If not passed a DB query will need to be run instead.
580
 * @return int The course_sections ID where the module is inserted
554
 * @return int The course_sections ID where the module is inserted
-
 
555
 * @throws moodle_exception if a module that has feature flag FEATURE_CAN_DISPLAY set to false is attempted to be moved to
-
 
556
 * a section number other than 0.
581
 */
557
 */
582
function course_add_cm_to_section($courseorid, $cmid, $sectionnum, $beforemod = null) {
558
function course_add_cm_to_section($courseorid, $cmid, $sectionnum, $beforemod = null, string $modname = '') {
583
    global $DB, $COURSE;
559
    global $DB, $COURSE;
584
    if (is_object($beforemod)) {
560
    if (is_object($beforemod)) {
585
        $beforemod = $beforemod->id;
561
        $beforemod = $beforemod->id;
586
    }
562
    }
587
    if (is_object($courseorid)) {
563
    if (is_object($courseorid)) {
588
        $courseid = $courseorid->id;
564
        $courseid = $courseorid->id;
589
    } else {
565
    } else {
590
        $courseid = $courseorid;
566
        $courseid = $courseorid;
591
    }
567
    }
-
 
568
 
-
 
569
    if (!$modname) {
-
 
570
        $sql = "SELECT name
-
 
571
                  FROM {modules} m
-
 
572
                  JOIN {course_modules} cm ON cm.module = m.id
-
 
573
                 WHERE cm.id = :cmid";
-
 
574
        $modname = $DB->get_field_sql($sql, ['cmid' => $cmid], MUST_EXIST);
-
 
575
    }
-
 
576
 
-
 
577
    // Modules not visible on the course must ALWAYS be in section 0.
-
 
578
    if ($sectionnum != 0 && !course_modinfo::is_mod_type_visible_on_course($modname)) {
-
 
579
        throw new moodle_exception("Modules with FEATURE_CAN_DISPLAY set to false can not be moved from section 0");
-
 
580
    }
-
 
581
 
592
    // Do not try to use modinfo here, there is no guarantee it is valid!
582
    // Do not try to use modinfo here, there is no guarantee it is valid!
593
    $section = $DB->get_record('course_sections',
583
    $section = $DB->get_record('course_sections',
594
            array('course' => $courseid, 'section' => $sectionnum), '*', IGNORE_MISSING);
584
            array('course' => $courseid, 'section' => $sectionnum), '*', IGNORE_MISSING);
595
    if (!$section) {
585
    if (!$section) {
596
        // This function call requires modinfo.
586
        // This function call requires modinfo.
Línea 676... Línea 666...
676
 *
666
 *
677
 * If $rebuildcache is set to false, the calling code is responsible for ensuring the cache is purged
667
 * If $rebuildcache is set to false, the calling code is responsible for ensuring the cache is purged
678
 * and rebuilt as appropriate. Consider using this if set_coursemodule_visible is called multiple times
668
 * and rebuilt as appropriate. Consider using this if set_coursemodule_visible is called multiple times
679
 * (e.g. in a loop).
669
 * (e.g. in a loop).
680
 *
670
 *
681
 * @param int $id of the module
671
 * @param int $cmid course module id
682
 * @param int $visible state of the module
672
 * @param int $visible state of the module
683
 * @param int $visibleoncoursepage state of the module on the course page
673
 * @param int $visibleoncoursepage state of the module on the course page
684
 * @param bool $rebuildcache If true (default), perform a partial cache purge and rebuild.
674
 * @param bool $rebuildcache If true (default), perform a partial cache purge and rebuild.
685
 * @return bool false when the module was not found, true otherwise
675
 * @return bool false when the module was not found, true otherwise
686
 */
676
 */
687
function set_coursemodule_visible($id, $visible, $visibleoncoursepage = 1, bool $rebuildcache = true) {
677
function set_coursemodule_visible($cmid, $visible, $visibleoncoursepage = 1, bool $rebuildcache = true) {
688
    global $DB, $CFG;
-
 
689
    require_once($CFG->libdir.'/gradelib.php');
-
 
690
    require_once($CFG->dirroot.'/calendar/lib.php');
-
 
691
 
-
 
692
    if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
-
 
693
        return false;
-
 
694
    }
-
 
695
 
-
 
696
    // Create events and propagate visibility to associated grade items if the value has changed.
-
 
697
    // Only do this if it's changed to avoid accidently overwriting manual showing/hiding of student grades.
-
 
698
    if ($cm->visible == $visible && $cm->visibleoncoursepage == $visibleoncoursepage) {
-
 
699
        return true;
-
 
700
    }
-
 
701
 
-
 
702
    if (!$modulename = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
-
 
703
        return false;
-
 
704
    }
-
 
705
    if (($cm->visible != $visible) &&
-
 
706
            ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename)))) {
-
 
707
        foreach($events as $event) {
-
 
708
            if ($visible) {
-
 
709
                $event = new calendar_event($event);
-
 
710
                $event->toggle_visibility(true);
-
 
711
            } else {
-
 
712
                $event = new calendar_event($event);
-
 
713
                $event->toggle_visibility(false);
-
 
714
            }
-
 
715
        }
-
 
716
    }
-
 
717
 
-
 
718
    // Updating visible and visibleold to keep them in sync. Only changing a section visibility will
-
 
719
    // affect visibleold to allow for an original visibility restore. See set_section_visible().
-
 
720
    $cminfo = new stdClass();
-
 
721
    $cminfo->id = $id;
-
 
722
    $cminfo->visible = $visible;
-
 
723
    $cminfo->visibleoncoursepage = $visibleoncoursepage;
-
 
724
    $cminfo->visibleold = $visible;
-
 
725
    $DB->update_record('course_modules', $cminfo);
-
 
726
 
-
 
727
    // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
-
 
728
    // Note that this must be done after updating the row in course_modules, in case
-
 
729
    // the modules grade_item_update function needs to access $cm->visible.
-
 
730
    if ($cm->visible != $visible &&
-
 
731
            plugin_supports('mod', $modulename, FEATURE_CONTROLS_GRADE_VISIBILITY) &&
-
 
732
            component_callback_exists('mod_' . $modulename, 'grade_item_update')) {
-
 
733
        $instance = $DB->get_record($modulename, array('id' => $cm->instance), '*', MUST_EXIST);
-
 
734
        component_callback('mod_' . $modulename, 'grade_item_update', array($instance));
678
    $coursecontext = context_module::instance($cmid)->get_course_context();
735
    } else if ($cm->visible != $visible) {
-
 
736
        $grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
679
    return formatactions::cm($coursecontext->instanceid)->set_visibility($cmid, $visible, $visibleoncoursepage, $rebuildcache);
737
        if ($grade_items) {
-
 
738
            foreach ($grade_items as $grade_item) {
-
 
739
                $grade_item->set_hidden(!$visible);
-
 
740
            }
-
 
741
        }
-
 
742
    }
-
 
743
 
-
 
744
    if ($rebuildcache) {
-
 
745
        \course_modinfo::purge_course_module_cache($cm->course, $cm->id);
-
 
746
        rebuild_course_cache($cm->course, false, true);
-
 
747
    }
-
 
748
    return true;
-
 
749
}
680
}
Línea 750... Línea 681...
750
 
681
 
751
/**
682
/**
752
 * Changes the course module name
683
 * Changes the course module name
Línea 813... Línea 744...
813
    } else {
744
    } else {
814
        throw new moodle_exception('cannotdeletemodulemissinglib', '', '', null,
745
        throw new moodle_exception('cannotdeletemodulemissinglib', '', '', null,
815
            "Cannot delete this module as the file mod/$modulename/lib.php is missing.");
746
            "Cannot delete this module as the file mod/$modulename/lib.php is missing.");
816
    }
747
    }
Línea -... Línea 748...
-
 
748
 
-
 
749
    // Warning! there is very similar code in remove_course_contents.
817
 
750
    // If you are changing this code, you probably need to change that too.
Línea 818... Línea 751...
818
    $deleteinstancefunction = $modulename . '_delete_instance';
751
    $deleteinstancefunction = $modulename . '_delete_instance';
819
 
752
 
820
    // Ensure the delete_instance function exists for this module.
753
    // Ensure the delete_instance function exists for this module.
Línea 830... Línea 763...
830
                $pluginfunction($cm);
763
                $pluginfunction($cm);
831
            }
764
            }
832
        }
765
        }
833
    }
766
    }
Línea -... Línea 767...
-
 
767
 
-
 
768
    if (empty($cm->instance)) {
-
 
769
        throw new moodle_exception('cannotdeletemodulemissinginstance', '', '', null,
-
 
770
            "Cannot delete course module with ID $cm->id because it does not have a valid activity instance.");
-
 
771
    }
834
 
772
 
835
    // Call the delete_instance function, if it returns false throw an exception.
773
    // Call the delete_instance function, if it returns false throw an exception.
836
    if (!$deleteinstancefunction($cm->instance)) {
774
    if (!$deleteinstancefunction($cm->instance)) {
837
        throw new moodle_exception('cannotdeletemoduleinstance', '', '', null,
775
        throw new moodle_exception('cannotdeletemoduleinstance', '', '', null,
838
            "Cannot delete the module $modulename (instance).");
776
            "Cannot delete the module $modulename (instance).");
Línea -... Línea 777...
-
 
777
    }
-
 
778
 
-
 
779
    // We delete the questions after the activity database is removed,
839
    }
780
    // because questions are referenced via question reference tables
Línea 840... Línea 781...
840
 
781
    // and cannot be deleted while the activities that use them still exist.
841
    question_delete_activity($cm);
782
    question_delete_activity($cm);
842
 
783
 
Línea 1117... Línea 1058...
1117
 * @param  stdClass $instance Module instance object.
1058
 * @param  stdClass $instance Module instance object.
1118
 * @param  stdClass $cm Course Module object.
1059
 * @param  stdClass $cm Course Module object.
1119
 * @since  Moodle 3.3.4
1060
 * @since  Moodle 3.3.4
1120
 */
1061
 */
1121
function course_module_calendar_event_update_process($instance, $cm) {
1062
function course_module_calendar_event_update_process($instance, $cm) {
-
 
1063
    global $CFG;
-
 
1064
 
1122
    // We need to call *_refresh_events() first because some modules delete 'old' events at the end of the code which
1065
    // We need to call *_refresh_events() first because some modules delete 'old' events at the end of the code which
1123
    // will remove the completion events.
1066
    // will remove the completion events.
-
 
1067
    include_once("$CFG->dirroot/mod/$cm->modname/lib.php");
1124
    $refresheventsfunction = $cm->modname . '_refresh_events';
1068
    $refresheventsfunction = $cm->modname . '_refresh_events';
1125
    if (function_exists($refresheventsfunction)) {
1069
    if (function_exists($refresheventsfunction)) {
1126
        call_user_func($refresheventsfunction, $cm->course, $instance, $cm);
1070
        call_user_func($refresheventsfunction, $cm->course, $instance, $cm);
1127
    }
1071
    }
1128
    $completionexpected = (!empty($cm->completionexpected)) ? $cm->completionexpected : null;
1072
    $completionexpected = (!empty($cm->completionexpected)) ? $cm->completionexpected : null;
Línea 1380... Línea 1324...
1380
 * @return int new value for module visibility (0 or 1)
1324
 * @return int new value for module visibility (0 or 1)
1381
 */
1325
 */
1382
function moveto_module($mod, $section, $beforemod=NULL) {
1326
function moveto_module($mod, $section, $beforemod=NULL) {
1383
    global $OUTPUT, $DB;
1327
    global $OUTPUT, $DB;
Línea -... Línea 1328...
-
 
1328
 
-
 
1329
    if ($section->section != 0 && !course_modinfo::is_mod_type_visible_on_course($mod->modname)) {
-
 
1330
        throw new coding_exception("Modules with FEATURE_CAN_DISPLAY set to false can not be moved from section 0");
-
 
1331
    }
1384
 
1332
 
1385
    // Current module visibility state - return value of this function.
1333
    // Current module visibility state - return value of this function.
Línea 1386... Línea 1334...
1386
    $modvisible = $mod->visible;
1334
    $modvisible = $mod->visible;
1387
 
1335
 
1388
    // Remove original module from original section.
1336
    // Remove original module from original section.
1389
    if (! delete_mod_from_section($mod->id, $mod->section)) {
1337
    if (! delete_mod_from_section($mod->id, $mod->section)) {
Línea 1390... Línea 1338...
1390
        echo $OUTPUT->notification("Could not delete module from existing section");
1338
        echo $OUTPUT->notification("Could not delete module from existing section");
1391
    }
1339
    }
Línea 1392... Línea 1340...
1392
 
1340
 
1393
    // Add the module into the new section.
1341
    // Add the module into the new section.
1394
    course_add_cm_to_section($section->course, $mod->id, $section->section, $beforemod);
1342
    course_add_cm_to_section($section->course, $mod->id, $section->section, $beforemod, $mod->modname);
1395
 
1343
 
Línea 1413... Línea 1361...
1413
}
1361
}
Línea 1414... Línea 1362...
1414
 
1362
 
1415
/**
1363
/**
1416
 * Returns the list of all editing actions that current user can perform on the module
1364
 * Returns the list of all editing actions that current user can perform on the module
-
 
1365
 *
-
 
1366
 * @deprecated since Moodle 5.0
-
 
1367
 * @todo Remove this method in Moodle 6.0 (MDL-83530).
1417
 *
1368
 *
1418
 * @param cm_info $mod The module to produce editing buttons for
1369
 * @param cm_info $mod The module to produce editing buttons for
1419
 * @param int $indent The current indenting (default -1 means no move left-right actions)
1370
 * @param int $indent The current indenting (default -1 means no move left-right actions)
1420
 * @param int $sr The section to link back to (used for creating the links)
1371
 * @param int $sr The section to link back to (used for creating the links)
1421
 * @return array array of action_link or pix_icon objects
1372
 * @return array array of action_link or pix_icon objects
-
 
1373
 */
-
 
1374
#[\core\attribute\deprecated(
-
 
1375
    replacement: 'core_courseformat\output\local\content\cm\controlmenu',
-
 
1376
    since: '5.0',
-
 
1377
    mdl: 'MDL-83527',
-
 
1378
    reason: 'Replaced by an output class equivalent.',
1422
 */
1379
)]
1423
function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
1380
function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
Línea -... Línea 1381...
-
 
1381
    global $COURSE, $SITE, $CFG;
-
 
1382
 
1424
    global $COURSE, $SITE, $CFG;
1383
    \core\deprecation::emit_deprecation(__FUNCTION__);
Línea 1425... Línea 1384...
1425
 
1384
 
1426
    static $str;
1385
    static $str;
1427
 
1386
 
1428
    $coursecontext = context_course::instance($mod->course);
1387
    $coursecontext = context_course::instance($mod->course);
1429
    $modcontext = context_module::instance($mod->id);
1388
    $modcontext = context_module::instance($mod->id);
-
 
1389
    $courseformat = course_get_format($mod->get_course());
Línea 1430... Línea 1390...
1430
    $courseformat = course_get_format($mod->get_course());
1390
    $usecomponents = $courseformat->supports_components();
1431
    $usecomponents = $courseformat->supports_components();
1391
    $sectioninfo = $mod->get_section_info();
Línea 1432... Línea 1392...
1432
    $sectioninfo = $mod->get_section_info();
1392
    $hasdelegatesection = sectiondelegate::has_delegate_class('mod_'.$mod->modname);
Línea 1462... Línea 1422...
1462
 
1422
 
1463
    // Update.
1423
    // Update.
1464
    if ($hasmanageactivities) {
1424
    if ($hasmanageactivities) {
1465
        $actions['update'] = new action_menu_link_secondary(
1425
        $actions['update'] = new action_menu_link_secondary(
1466
            new moodle_url($baseurl, array('update' => $mod->id)),
1426
            new moodle_url($baseurl, array('update' => $mod->id)),
1467
            new pix_icon('t/edit', '', 'moodle', array('class' => 'iconsmall')),
1427
            new pix_icon('i/settings', '', 'moodle', ['class' => 'iconsmall']),
1468
            $str->editsettings,
1428
            $str->editsettings,
1469
            array('class' => 'editing_update', 'data-action' => 'update')
1429
            array('class' => 'editing_update', 'data-action' => 'update')
1470
        );
1430
        );
Línea 1486... Línea 1446...
1486
            ]
1446
            ]
1487
        );
1447
        );
1488
    }
1448
    }
Línea 1489... Línea 1449...
1489
 
1449
 
1490
    // Indent.
1450
    // Indent.
1491
    if ($hasmanageactivities && $indent >= 0) {
1451
    if ($hasmanageactivities && $indent >= 0 && !$hasdelegatesection) {
1492
        $indentlimits = new stdClass();
1452
        $indentlimits = new stdClass();
1493
        $indentlimits->min = 0;
1453
        $indentlimits->min = 0;
1494
        // Legacy indentation could continue using a limit of 16,
1454
        // Legacy indentation could continue using a limit of 16,
1495
        // but components based formats will be forced to use one level indentation only.
1455
        // but components based formats will be forced to use one level indentation only.
Línea 1567... Línea 1527...
1567
            ]
1527
            ]
1568
        );
1528
        );
1569
    }
1529
    }
Línea 1570... Línea 1530...
1570
 
1530
 
1571
    // Assign.
1531
    // Assign.
1572
    if (has_capability('moodle/role:assign', $modcontext)){
1532
    if (has_capability('moodle/role:assign', $modcontext) && !$hasdelegatesection) {
1573
        $actions['assign'] = new action_menu_link_secondary(
1533
        $actions['assign'] = new action_menu_link_secondary(
1574
            new moodle_url('/admin/roles/assign.php', array('contextid' => $modcontext->id)),
1534
            new moodle_url('/admin/roles/assign.php', array('contextid' => $modcontext->id)),
1575
            new pix_icon('t/assignroles', '', 'moodle', array('class' => 'iconsmall')),
1535
            new pix_icon('t/assignroles', '', 'moodle', array('class' => 'iconsmall')),
1576
            $str->assign,
1536
            $str->assign,
Línea 1684... Línea 1644...
1684
 * @param object $course the course settings. Only $course->id is used.
1644
 * @param object $course the course settings. Only $course->id is used.
1685
 * @param string $modname the module name. E.g. 'forum' or 'quiz'.
1645
 * @param string $modname the module name. E.g. 'forum' or 'quiz'.
1686
 * @param \stdClass $user the user to check, defaults to the global user if not provided.
1646
 * @param \stdClass $user the user to check, defaults to the global user if not provided.
1687
 * @return bool whether the current user is allowed to add this type of module to this course.
1647
 * @return bool whether the current user is allowed to add this type of module to this course.
1688
 */
1648
 */
1689
function course_allowed_module($course, $modname, \stdClass $user = null) {
1649
function course_allowed_module($course, $modname, ?\stdClass $user = null) {
1690
    global $USER;
1650
    global $USER;
1691
    $user = $user ?? $USER;
1651
    $user = $user ?? $USER;
1692
    if (is_numeric($modname)) {
1652
    if (is_numeric($modname)) {
1693
        throw new coding_exception('Function course_allowed_module no longer
1653
        throw new coding_exception('Function course_allowed_module no longer
1694
                supports numeric module ids. Please update your code to pass the module name.');
1654
                supports numeric module ids. Please update your code to pass the module name.');
Línea 1778... Línea 1738...
1778
 *
1738
 *
1779
 * Implementation of this function is provided by course format
1739
 * Implementation of this function is provided by course format
1780
 * @see core_courseformat\base::get_section_name()
1740
 * @see core_courseformat\base::get_section_name()
1781
 *
1741
 *
1782
 * @param int|stdClass $courseorid The course to get the section name for (object or just course id)
1742
 * @param int|stdClass $courseorid The course to get the section name for (object or just course id)
1783
 * @param int|stdClass $section Section object from database or just field course_sections.section
1743
 * @param int|stdClass|section_info $section Section object from database or just field course_sections.section
1784
 * @return string Display name that the course format prefers, e.g. "Week 2"
1744
 * @return string Display name that the course format prefers, e.g. "Week 2"
1785
 */
1745
 */
1786
function get_section_name($courseorid, $section) {
1746
function get_section_name($courseorid, $section) {
1787
    return course_get_format($courseorid)->get_section_name($section);
1747
    return course_get_format($courseorid)->get_section_name($section);
1788
}
1748
}
Línea 1803... Línea 1763...
1803
 * Returns the information about the ajax support in the given source format
1763
 * Returns the information about the ajax support in the given source format
1804
 *
1764
 *
1805
 * The returned object's property (boolean)capable indicates that
1765
 * The returned object's property (boolean)capable indicates that
1806
 * the course format supports Moodle course ajax features.
1766
 * the course format supports Moodle course ajax features.
1807
 *
1767
 *
-
 
1768
 * @deprecated since Moodle 5.0 MDL-82351
-
 
1769
 * @todo MDL-83417 Remove this function in Moodle 6.0
1808
 * @param string $format
1770
 * @param string $format
1809
 * @return stdClass
1771
 * @return stdClass
1810
 */
1772
 */
-
 
1773
#[\core\attribute\deprecated(since: '5.0', mdl: 'MDL-82351')]
1811
function course_format_ajax_support($format) {
1774
function course_format_ajax_support($format) {
-
 
1775
    \core\deprecation::emit_deprecation(__FUNCTION__);
1812
    $course = new stdClass();
1776
    $course = new stdClass();
1813
    $course->format = $format;
1777
    $course->format = $format;
1814
    return course_get_format($course)->supports_ajax();
1778
    return course_get_format($course)->supports_ajax();
1815
}
1779
}
Línea 2277... Línea 2241...
2277
 *
2241
 *
2278
 * @param bool $onlyactive Consider only active enrolments in enabled plugins and obey the enrolment time restrictions.
2242
 * @param bool $onlyactive Consider only active enrolments in enabled plugins and obey the enrolment time restrictions.
2279
 * @param int $lastloginsince If specified, count only users who logged in after this timestamp.
2243
 * @param int $lastloginsince If specified, count only users who logged in after this timestamp.
2280
 * @return float
2244
 * @return float
2281
 */
2245
 */
2282
function average_number_of_participants(bool $onlyactive = false, int $lastloginsince = null): float {
2246
function average_number_of_participants(bool $onlyactive = false, ?int $lastloginsince = null): float {
2283
    global $DB;
2247
    global $DB;
Línea 2284... Línea 2248...
2284
 
2248
 
Línea 2285... Línea 2249...
2285
    $params = [];
2249
    $params = [];
Línea 2691... Línea 2655...
2691
        }
2655
        }
Línea 2692... Línea 2656...
2692
 
2656
 
Línea 2693... Línea 2657...
2693
        $this->delete();
2657
        $this->delete();
2694
 
2658
 
2695
        $a = new stdClass();
2659
        $a = new stdClass();
-
 
2660
        $a->name = format_string($course->fullname, true, ['context' => $context]);
-
 
2661
        $a->url = course_get_url($course);
-
 
2662
 
-
 
2663
        $usernameplaceholders = \core\user::get_name_placeholders($user);
-
 
2664
        foreach ($usernameplaceholders as $field => $value) {
-
 
2665
            $a->{$field} = $value;
2696
        $a->name = format_string($course->fullname, true, array('context' => context_course::instance($course->id)));
2666
        }
Línea 2697... Línea 2667...
2697
        $a->url = $CFG->wwwroot.'/course/view.php?id=' . $course->id;
2667
 
2698
        $this->notify($user, $USER, 'courserequestapproved', get_string('courseapprovedsubject'), get_string('courseapprovedemail2', 'moodle', $a), $course->id);
2668
        $this->notify($user, $USER, 'courserequestapproved', get_string('courseapprovedsubject'), get_string('courseapprovedemail2', 'moodle', $a), $course->id);
Línea 2823... Línea 2793...
2823
    }
2793
    }
Línea 2824... Línea 2794...
2824
 
2794
 
2825
    // Check that the course format supports ajax functionality
2795
    // Check that the course format supports ajax functionality
2826
    // The site 'format' doesn't have information on course format support
2796
    // The site 'format' doesn't have information on course format support
2827
    if ($SITE->id !== $course->id) {
2797
    if ($SITE->id !== $course->id) {
2828
        $courseformatajaxsupport = course_format_ajax_support($course->format);
2798
        $courseformatajaxsupport = course_get_format($course)->supports_ajax();
2829
        if (!$courseformatajaxsupport->capable) {
2799
        if (!$courseformatajaxsupport->capable) {
2830
            return false;
2800
            return false;
2831
        }
2801
        }
Línea 2846... Línea 2816...
2846
 *          * resourceurl   The URL to post changes to for resource changes
2816
 *          * resourceurl   The URL to post changes to for resource changes
2847
 *          * sectionurl    The URL to post changes to for section changes
2817
 *          * sectionurl    The URL to post changes to for section changes
2848
 *          * pageparams    Additional parameters to pass through in the post
2818
 *          * pageparams    Additional parameters to pass through in the post
2849
 * @return bool
2819
 * @return bool
2850
 */
2820
 */
2851
function include_course_ajax($course, $usedmodules = array(), $enabledmodules = null, $config = null) {
2821
function include_course_ajax($course, $usedmodules = [], $enabledmodules = null, $config = null) {
2852
    global $CFG, $PAGE, $SITE;
2822
    global $CFG, $PAGE, $SITE;
Línea 2853... Línea 2823...
2853
 
2823
 
2854
    // Init the course editor module to support UI components.
2824
    // Init the course editor module to support UI components.
2855
    $format = course_get_format($course);
2825
    $format = course_get_format($course);
Línea -... Línea 2826...
-
 
2826
    include_course_editor($format);
2856
    include_course_editor($format);
2827
 
2857
 
2828
    // TODO remove this if as part of MDL-83627.
2858
    // Ensure that ajax should be included
2829
    // Ensure that ajax should be included
2859
    if (!course_ajax_enabled($course)) {
2830
    if (!course_ajax_enabled($course)) {
Línea -... Línea 2831...
-
 
2831
        return false;
2860
        return false;
2832
    }
2861
    }
2833
 
-
 
2834
    // TODO remove this if as part of MDL-83627.
-
 
2835
    // Component based formats don't use YUI drag and drop anymore.
-
 
2836
    if (!$format->supports_components() && course_format_uses_sections($course->format)) {
-
 
2837
        debugging(
Línea 2862... Línea 2838...
2862
 
2838
            'The old course editor will be removed in Moodle 6.0. Ensure your format return true to supports_components',
2863
    // Component based formats don't use YUI drag and drop anymore.
2839
            DEBUG_DEVELOPER
2864
    if (!$format->supports_components() && course_format_uses_sections($course->format)) {
2840
        );
Línea 2935... Línea 2911...
2935
        }
2911
        }
Línea 2936... Línea 2912...
2936
 
2912
 
2937
        // Load drag and drop upload AJAX.
2913
        // Load drag and drop upload AJAX.
2938
        require_once($CFG->dirroot.'/course/dnduploadlib.php');
2914
        require_once($CFG->dirroot.'/course/dnduploadlib.php');
2939
        dndupload_add_to_course($course, $enabledmodules);
-
 
Línea 2940... Línea 2915...
2940
    }
2915
        dndupload_add_to_course($course, $enabledmodules);
-
 
2916
 
Línea 2941... Línea 2917...
2941
 
2917
        $PAGE->requires->js_call_amd('core_course/actions', 'initCoursePage', [$course->format]);
2942
    $PAGE->requires->js_call_amd('core_course/actions', 'initCoursePage', array($course->format));
2918
    }
Línea 2943... Línea 2919...
2943
 
2919
 
Línea 2952... Línea 2928...
2952
function include_course_editor(course_format $format) {
2928
function include_course_editor(course_format $format) {
2953
    global $PAGE, $SITE;
2929
    global $PAGE, $SITE;
Línea 2954... Línea 2930...
2954
 
2930
 
Línea 2955... Línea 2931...
2955
    $course = $format->get_course();
2931
    $course = $format->get_course();
2956
 
2932
 
2957
    if ($SITE->id === $course->id) {
2933
    if (!$format->supports_ajax()?->capable) {
Línea 2958... Línea 2934...
2958
        return;
2934
        return;
Línea 2979... Línea 2955...
2979
 * @return array array of sorted format names
2955
 * @return array array of sorted format names
2980
 */
2956
 */
2981
function get_sorted_course_formats($enabledonly = false) {
2957
function get_sorted_course_formats($enabledonly = false) {
2982
    global $CFG;
2958
    global $CFG;
Línea -... Línea 2959...
-
 
2959
 
-
 
2960
    // Include both formats that exist on disk (but might not have been installed yet), and those
2983
 
2961
    // which were installed but no longer exist on disk.
-
 
2962
    $installedformats = core_plugin_manager::instance()->get_installed_plugins('format');
-
 
2963
    $existingformats = core_component::get_plugin_list('format');
Línea 2984... Línea 2964...
2984
    $formats = core_plugin_manager::instance()->get_installed_plugins('format');
2964
    $formats = array_merge($installedformats, $existingformats);
2985
 
2965
 
2986
    if (!empty($CFG->format_plugins_sortorder)) {
2966
    if (!empty($CFG->format_plugins_sortorder)) {
2987
        $order = explode(',', $CFG->format_plugins_sortorder);
2967
        $order = explode(',', $CFG->format_plugins_sortorder);
Línea 3146... Línea 3126...
3146
 * @throws moodle_exception
3126
 * @throws moodle_exception
3147
 * @throws restore_controller_exception
3127
 * @throws restore_controller_exception
3148
 *
3128
 *
3149
 * @return cm_info|null cminfo object if we sucessfully duplicated the mod and found the new cm.
3129
 * @return cm_info|null cminfo object if we sucessfully duplicated the mod and found the new cm.
3150
 */
3130
 */
3151
function duplicate_module($course, $cm, int $sectionid = null, bool $changename = true): ?cm_info {
3131
function duplicate_module($course, $cm, ?int $sectionid = null, bool $changename = true): ?cm_info {
3152
    global $CFG, $DB, $USER;
3132
    global $CFG, $DB, $USER;
3153
    require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
3133
    require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
3154
    require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
3134
    require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
3155
    require_once($CFG->libdir . '/filelib.php');
3135
    require_once($CFG->libdir . '/filelib.php');
Línea -... Línea 3136...
-
 
3136
 
-
 
3137
    // Plugins with this feature flag set to false must ALWAYS be in section 0.
-
 
3138
    if (!course_modinfo::is_mod_type_visible_on_course($cm->modname)) {
-
 
3139
        if (get_fast_modinfo($course)->get_section_info(0, MUST_EXIST)->id != $sectionid) {
-
 
3140
            throw new coding_exception('Modules with FEATURE_CAN_DISPLAY set to false can not be moved from section 0');
-
 
3141
        }
-
 
3142
    }
3156
 
3143
 
3157
    $a          = new stdClass();
3144
    $a          = new stdClass();
3158
    $a->modtype = get_string('modulename', $cm->modname);
3145
    $a->modtype = get_string('modulename', $cm->modname);
Línea 3159... Línea 3146...
3159
    $a->modname = format_string($cm->name);
3146
    $a->modname = format_string($cm->name);
Línea 3709... Línea 3696...
3709
        'notes' => false,
3696
        'notes' => false,
3710
        'participants' => false,
3697
        'participants' => false,
3711
        'search' => false,
3698
        'search' => false,
3712
        'tags' => false,
3699
        'tags' => false,
3713
        'communication' => false,
3700
        'communication' => false,
-
 
3701
        'overview' => false,
3714
    ];
3702
    ];
Línea 3715... Línea 3703...
3715
 
3703
 
3716
    $options->blogs = !empty($CFG->enableblogs) &&
3704
    $options->blogs = !empty($CFG->enableblogs) &&
3717
                        ($CFG->bloglevel == BLOG_GLOBAL_LEVEL ||
3705
                        ($CFG->bloglevel == BLOG_GLOBAL_LEVEL ||
Línea 3788... Línea 3776...
3788
 
3776
 
3789
    if (\core_competency\api::is_enabled()) {
3777
    if (\core_competency\api::is_enabled()) {
3790
        $capabilities = array('moodle/competency:coursecompetencyview', 'moodle/competency:coursecompetencymanage');
3778
        $capabilities = array('moodle/competency:coursecompetencyview', 'moodle/competency:coursecompetencymanage');
3791
        $options->competencies = has_any_capability($capabilities, $context);
3779
        $options->competencies = has_any_capability($capabilities, $context);
-
 
3780
    }
-
 
3781
 
-
 
3782
    if ($isloggedin && !$isfrontpage) {
-
 
3783
        $options->overview = has_capability('moodle/course:viewoverview', $context);
-
 
3784
    }
3792
    }
3785
 
3793
    return $options;
3786
    return $options;
Línea 3794... Línea 3787...
3794
}
3787
}
3795
 
3788
 
3796
/**
3789
/**
3797
 * Return an object with the list of administration options in a course that are available or not for the current user.
3790
 * Return an object with the list of administration options in a course that are available or not for the current user.
3798
 * This function also handles the frontpage settings.
3791
 * This function also handles the frontpage settings.
3799
 *
3792
 *
3800
 * @param  stdClass $course  course object (for frontpage it should be a clone of $SITE)
3793
 * @param  stdClass $course  course object (for frontpage it should be a clone of $SITE)
3801
 * @param  stdClass $context context object (course context)
3794
 * @param  context_course $context context object (course context)
3802
 * @return stdClass          the administration options in a course and their availability status
3795
 * @return stdClass          the administration options in a course and their availability status
3803
 * @since  Moodle 3.2
3796
 * @since  Moodle 3.2
3804
 */
3797
 */
-
 
3798
function course_get_user_administration_options($course, $context) {
3805
function course_get_user_administration_options($course, $context) {
3799
    global $CFG;
3806
    global $CFG;
-
 
3807
    $isfrontpage = $course->id == SITEID;
3800
 
3808
    $completionenabled = $CFG->enablecompletion && $course->enablecompletion;
3801
    $isfrontpage = $course->id == SITEID;
3809
    $hascompletionoptions = count(core_completion\manager::get_available_completion_options($course->id)) > 0;
3802
    $hascompletionoptions = count(core_completion\manager::get_available_completion_options($course->id)) > 0;
3810
    $options = new stdClass;
3803
    $options = new stdClass;
3811
    $options->update = has_capability('moodle/course:update', $context);
3804
    $options->update = has_capability('moodle/course:update', $context);
Línea 3818... Línea 3811...
3818
    $options->restore = has_capability('moodle/restore:restorecourse', $context);
3811
    $options->restore = has_capability('moodle/restore:restorecourse', $context);
3819
    $options->copy = \core_course\management\helper::can_copy_course($course->id);
3812
    $options->copy = \core_course\management\helper::can_copy_course($course->id);
3820
    $options->files = ($course->legacyfiles == 2 && has_capability('moodle/course:managefiles', $context));
3813
    $options->files = ($course->legacyfiles == 2 && has_capability('moodle/course:managefiles', $context));
Línea 3821... Línea 3814...
3821
 
3814
 
3822
    if (!$isfrontpage) {
3815
    if (!$isfrontpage) {
3823
        $options->tags = has_capability('moodle/course:tag', $context);
3816
        $options->tags = core_tag_tag::is_enabled('core', 'course') && has_capability('moodle/course:tag', $context);
3824
        $options->gradebook = has_capability('moodle/grade:manage', $context);
3817
        $options->gradebook = has_capability('moodle/grade:manage', $context);
3825
        $options->outcomes = !empty($CFG->enableoutcomes) && has_capability('moodle/course:update', $context);
3818
        $options->outcomes = !empty($CFG->enableoutcomes) && has_capability('moodle/course:update', $context);
3826
        $options->badges = !empty($CFG->enablebadges);
3819
        $options->badges = !empty($CFG->enablebadges);
3827
        $options->import = has_capability('moodle/restore:restoretargetimport', $context);
3820
        $options->import = has_capability('moodle/restore:restoretargetimport', $context);
Línea 4057... Línea 4050...
4057
 * @return Generator
4050
 * @return Generator
4058
 */
4051
 */
4059
function course_get_enrolled_courses_for_logged_in_user(
4052
function course_get_enrolled_courses_for_logged_in_user(
4060
    int $limit = 0,
4053
    int $limit = 0,
4061
    int $offset = 0,
4054
    int $offset = 0,
4062
    string $sort = null,
4055
    ?string $sort = null,
4063
    string $fields = null,
4056
    ?string $fields = null,
4064
    int $dbquerylimit = COURSE_DB_QUERY_LIMIT,
4057
    int $dbquerylimit = COURSE_DB_QUERY_LIMIT,
4065
    array $includecourses = [],
4058
    array $includecourses = [],
4066
    array $hiddencourses = []
4059
    array $hiddencourses = []
4067
): Generator {
4060
): Generator {
Línea 4103... Línea 4096...
4103
 * @return Generator
4096
 * @return Generator
4104
 */
4097
 */
4105
function course_get_enrolled_courses_for_logged_in_user_from_search(
4098
function course_get_enrolled_courses_for_logged_in_user_from_search(
4106
    int $limit = 0,
4099
    int $limit = 0,
4107
    int $offset = 0,
4100
    int $offset = 0,
4108
    string $sort = null,
4101
    ?string $sort = null,
4109
    string $fields = null,
4102
    ?string $fields = null,
4110
    int $dbquerylimit = COURSE_DB_QUERY_LIMIT,
4103
    int $dbquerylimit = COURSE_DB_QUERY_LIMIT,
4111
    array $searchcriteria = [],
4104
    array $searchcriteria = [],
4112
    array $options = []
4105
    array $options = []
4113
): Generator {
4106
): Generator {
Línea 4492... Línea 4485...
4492
 * @param string $filearea the backup file area. E.g. 'course', 'backup' or 'automated'.
4485
 * @param string $filearea the backup file area. E.g. 'course', 'backup' or 'automated'.
4493
 * @param \context $context
4486
 * @param \context $context
4494
 * @param stdClass $user the user object. If not provided, the current user will be checked.
4487
 * @param stdClass $user the user object. If not provided, the current user will be checked.
4495
 * @return bool true if the user is allowed to download in the context, false otherwise.
4488
 * @return bool true if the user is allowed to download in the context, false otherwise.
4496
 */
4489
 */
4497
function can_download_from_backup_filearea($filearea, \context $context, stdClass $user = null) {
4490
function can_download_from_backup_filearea($filearea, \context $context, ?stdClass $user = null) {
4498
    $candownload = false;
4491
    $candownload = false;
4499
    switch ($filearea) {
4492
    switch ($filearea) {
4500
        case 'course':
4493
        case 'course':
4501
        case 'backup':
4494
        case 'backup':
4502
            $candownload = has_capability('moodle/backup:downloadfile', $context, $user);
4495
            $candownload = has_capability('moodle/backup:downloadfile', $context, $user);
Línea 4548... Línea 4541...
4548
 * @param int $limit Restrict result set to this amount
4541
 * @param int $limit Restrict result set to this amount
4549
 * @param int $offset Skip this number of records from the start of the result set
4542
 * @param int $offset Skip this number of records from the start of the result set
4550
 * @param string|null $sort SQL string for sorting
4543
 * @param string|null $sort SQL string for sorting
4551
 * @return array
4544
 * @return array
4552
 */
4545
 */
4553
function course_get_recent_courses(int $userid = null, int $limit = 0, int $offset = 0, string $sort = null) {
4546
function course_get_recent_courses(?int $userid = null, int $limit = 0, int $offset = 0, ?string $sort = null) {
Línea 4554... Línea 4547...
4554
 
4547
 
Línea 4555... Línea 4548...
4555
    global $CFG, $USER, $DB;
4548
    global $CFG, $USER, $DB;
4556
 
4549
 
Línea 4841... Línea 4834...
4841
 
4834
 
4842
    return $o;
4835
    return $o;
Línea 4843... Línea 4836...
4843
}
4836
}
-
 
4837
 
-
 
4838
/**
-
 
4839
 * Get the course overview fragment.
-
 
4840
 *
-
 
4841
 * @param array $args the fragment arguments
-
 
4842
 * @return string the course overview fragment
-
 
4843
 */
-
 
4844
function course_output_fragment_course_overview($args) {
-
 
4845
    global $PAGE;
-
 
4846
    if (empty($args['modname']) || empty($args['courseid'])) {
-
 
4847
        throw new coding_exception('modname and courseid are required');
-
 
4848
    }
-
 
4849
    $modname = $args['modname'];
-
 
4850
    $course = get_course($args['courseid']);
-
 
4851
    $context = context_course::instance($course->id, MUST_EXIST);
-
 
4852
    can_access_course($course);
-
 
4853
 
-
 
4854
    // Some plugins may have a list view event.
-
 
4855
    $eventclassname = 'mod_' . $modname . '\\event\\course_module_instance_list_viewed';
-
 
4856
    // Do not confuse this "resource" with the "mod_resource" module.
-
 
4857
    // This "resource" is the table that aggregate all activities considered "resources"
-
 
4858
    // (files, folders, pages, text and media...). While the "mod_resource" is a poorly
-
 
4859
    // named plugin representing an uploaded file, and it is also one of the activities
-
 
4860
    // that can be aggregated in the "resource" table.
-
 
4861
    if ($modname === 'resource') {
-
 
4862
        $eventclassname = 'core\\event\\course_resources_list_viewed';
-
 
4863
    }
-
 
4864
    if (class_exists($eventclassname)) {
-
 
4865
        try {
-
 
4866
            $event = $eventclassname::create(['context' => $context]);
-
 
4867
            $event->add_record_snapshot('course', $course);
-
 
4868
            $event->trigger();
-
 
4869
        } catch (\Throwable $th) {
-
 
4870
            // This may happens if the plugin implements a custom event class.
-
 
4871
            // It is highly unlikely but we should not stop the rendering because of this.
-
 
4872
            // Instead, we will log the error and continue.
-
 
4873
            debugging('Error while triggering the course module instance viewed event: ' . $th->getMessage());
-
 
4874
        }
-
 
4875
    }
-
 
4876
 
-
 
4877
    $content = '';
-
 
4878
    $format = course_get_format($course);
-
 
4879
    $renderer = $format->get_renderer($PAGE);
-
 
4880
 
-
 
4881
    // Plugins with not implemented overview table will have an extra link to the index.php.
-
 
4882
    $overvietableclass = $format->get_output_classname('overview\missingoverviewnotice');
-
 
4883
    /** @var \core_courseformat\output\local\overview\missingoverviewnotice $output */
-
 
4884
    $output = new $overvietableclass($course, $modname);
-
 
4885
    $content .= $renderer->render($output);
-
 
4886
 
-
 
4887
    $overvietableclass = $format->get_output_classname('overview\\overviewtable');
-
 
4888
    /** @var \core_courseformat\output\local\overview\overviewtable $output */
-
 
4889
    $output = new $overvietableclass($course, $modname);
-
 
4890
    $content .= $renderer->render($output);
-
 
4891
 
-
 
4892
    return $content;
-
 
4893
}
4844
 
4894
 
4845
/**
4895
/**
4846
 * Get the current course image for the given course.
4896
 * Get the current course image for the given course.
4847
 *
4897
 *
4848
 * @param \stdClass $course
4898
 * @param \stdClass $course
Línea 4882... Línea 4932...
4882
 *
4932
 *
4883
 * @param stdClass $data The data to update the course with.
4933
 * @param stdClass $data The data to update the course with.
4884
 */
4934
 */
4885
function course_update_communication_instance_data(stdClass $data): void {
4935
function course_update_communication_instance_data(stdClass $data): void {
4886
    $data->id = $data->instanceid; // For correct use in update_course.
4936
    $data->id = $data->instanceid; // For correct use in update_course.
-
 
4937
    // If the room name is set to empty, then set it course name.
-
 
4938
    $provider = $data->selectedcommunication ?? null;
-
 
4939
    $roomnameidentifier = $provider . 'roomname';
-
 
4940
    if ($provider && empty($data->$roomnameidentifier)) {
-
 
4941
        $data->$roomnameidentifier = $data->fullname ?? get_course($data->id)->fullname;
-
 
4942
    }
4887
    core_communication\helper::update_course_communication_instance(
4943
    core_communication\helper::update_course_communication_instance(
4888
        course: $data,
4944
        course: $data,
4889
        changesincoursecat: false,
4945
        changesincoursecat: false,
4890
    );
4946
    );
4891
}
4947
}