Fixed for a few bugs

This commit is contained in:
PMKuipers 2023-08-31 07:40:55 +02:00
parent 6c7e489956
commit ef7f037776
40 changed files with 31057 additions and 42442 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

30803
amd/src/bootstrap-vue/bootstrap-vue.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,17 @@
Instructions for downloading and integrating bootstrap-vue and associoated files Instructions for downloading and integrating bootstrap-vue and associated files
Note: Using bootstrap-vue.esm.js gives unexpected problems with Form components with multi-select not showing proper values
in the list, but the text fields instead.
That's why the plain bootstrap.js file is used
1. download bootstrap-vue distribusion through npm 1. download bootstrap-vue distribusion through npm
npm install bootstrap-vue@2.23.1 npm install bootstrap-vue@2.23.1
2. Copy node_modules/bootstrap-vue/dist/bootstrap-vue.esm.js to amd/src/bootstrap-vue 2. Copy node_modules/bootstrap-vue/dist/bootstrap-vue.js to amd/src/bootstrap-vue
Copy node_modules/bootstrap-vue/dist/bootstrap-vue.min.css to css/bootstrap-vue Copy node_modules/bootstrap-vue/dist/bootstrap-vue.min.css to css/bootstrap-vue
3. Change import statements on top of bootstrap-vue.esm to: 3. Change require("vue"...) and define("vue"...) in the lines 10 - 16 to
require("../vue/vue"...) and define("../vue/vue"...)
/* Path modifications by PMKuipers to handle relative loading of vue in moodle context*/
import Vue from '../vue/vue';
import { mergeData } from './vue-functional-data-merge';
import Popper from 'core/popper'; // Popper is included in core
import { Wormhole, PortalTarget, Portal } from '../portal-vue/portal-vue.esm';
/* End modifications */
4. add /* eslint-disable */ to top of bootstrap-vue.esm.js 4. add /* eslint-disable */ to top of bootstrap-vue.esm.js

View File

@ -29,7 +29,7 @@ import {download,upload} from './downloader';
import PortalVue from './portal-vue/portal-vue.esm'; import PortalVue from './portal-vue/portal-vue.esm';
Vue.use(PortalVue); Vue.use(PortalVue);
import BootstrapVue from './bootstrap-vue/bootstrap-vue.esm'; import BootstrapVue from './bootstrap-vue/bootstrap-vue';
Vue.use(BootstrapVue); Vue.use(BootstrapVue);
import {Drag, Drop, DropList} from './vue-easy-dnd/vue-easy-dnd.esm'; import {Drag, Drop, DropList} from './vue-easy-dnd/vue-easy-dnd.esm';

View File

@ -25,7 +25,7 @@ Vue.use(ModalComponents);
import PortalVue from './portal-vue/portal-vue.esm'; import PortalVue from './portal-vue/portal-vue.esm';
Vue.use(PortalVue); Vue.use(PortalVue);
import BootstrapVue from './bootstrap-vue/bootstrap-vue.esm'; import BootstrapVue from './bootstrap-vue/bootstrap-vue';
Vue.use(BootstrapVue); Vue.use(BootstrapVue);

View File

@ -91,6 +91,8 @@ export default {
coursetiming_present: "coursetiming_present", coursetiming_present: "coursetiming_present",
coursetiming_future: "coursetiming_future", coursetiming_future: "coursetiming_future",
required_goal: "required_goal", required_goal: "required_goal",
student_not_tracked: "student_not_tracked",
not_enrolled: "not_enrolled",
}, },
teachercourse: { teachercourse: {
select_conditions: "select_conditions", select_conditions: "select_conditions",
@ -101,6 +103,8 @@ export default {
grade_include: "grade_include", grade_include: "grade_include",
grade_require: "grade_require", grade_require: "grade_require",
required_goal: "required_goal", required_goal: "required_goal",
student_from_plan_enrolled: "student_from_plan_enrolled",
students_from_plan_enrolled: "student_from_plan_enrolled",
} }
}); });
@ -896,7 +900,12 @@ export default {
</b-col> </b-col>
<b-col md="11" class="align-items-center"> <b-col md="11" class="align-items-center">
<b-card-body > <b-card-body >
<template v-if='value.course.completion'> <template v-if='!value.course.enrolled'>
<i v-b-popover.top
class="r-course-result fa fa-exclamation-triangle t-not-enrolled-alert"
:title="text.student_not_tracked"></i>
</template>
<template v-else-if='value.course.completion'>
<r-progress-circle v-if='["failed", "progress","incomplete"].includes(value.completion)' <r-progress-circle v-if='["failed", "progress","incomplete"].includes(value.completion)'
:value='value.course.completion.progress' :value='value.course.completion.progress'
:max='value.course.completion.count' :max='value.course.completion.count'
@ -940,7 +949,13 @@ export default {
</div> </div>
<div class="r-course-detail-header-right"> <div class="r-course-detail-header-right">
<div class="r-completion-detail-header"> <div class="r-completion-detail-header">
<template v-if='value.course.completion'> <template v-if='!value.course.enrolled'>
{{text.not_enrolled}}
<i v-b-popover.top
class="r-course-result fa fa-exclamation-triangle t-not-enrolled-alert"
:title="text.student_not_tracked"></i>
</template>
<template v-else-if='value.course.completion'>
{{text['completion_'+value.completion]}} {{text['completion_'+value.completion]}}
<r-progress-circle v-if='["failed","progress","incomplete"].includes(value.completion)' <r-progress-circle v-if='["failed","progress","incomplete"].includes(value.completion)'
:value='value.course.completion.progress' :value='value.course.completion.progress'
@ -1109,6 +1124,8 @@ export default {
coursetiming_present: "coursetiming_present", coursetiming_present: "coursetiming_present",
coursetiming_future: "coursetiming_future", coursetiming_future: "coursetiming_future",
required_goal: "required_goal", required_goal: "required_goal",
student_not_tracked: "student_not_tracked",
completion_not_enabled: "completion_not_enabled",
}, },
}; };
}, },
@ -1151,7 +1168,7 @@ export default {
}, },
template: ` template: `
<table class="r-item-course-grade-details"> <table class="r-item-course-grade-details">
<template v-for='cgroup in value.conditions'> <template v-for='cgroup in value.conditions' v-if='value.enabled && value.tracked'>
<tr> <tr>
<th colspan='2'>{{cgroup.title}}</th> <th colspan='2'>{{cgroup.title}}</th>
<th><r-progress-circle v-if="cgroup.progress < cgroup.count" <th><r-progress-circle v-if="cgroup.progress < cgroup.count"
@ -1197,6 +1214,14 @@ export default {
</td> </td>
</tr> </tr>
</template> </template>
<template v-else>
<tr v-if='! value.enabled'>
<td colspan='4'>{{text.completion_not_enabled}}</td>
</tr>
<tr v-else>
<td colspan='4'>{{text.student_not_tracked}}</td>
</tr>
</template>
</table> </table>
`, `,
}); });
@ -1427,6 +1452,10 @@ export default {
:title="text.configure_completion"><i class="fa fa-gear"></i></a> :title="text.configure_completion"><i class="fa fa-gear"></i></a>
</h1> </h1>
{{ value.course.context.path.join(" / ")}} {{ value.course.context.path.join(" / ")}}
<div class='mt-1 text-info'>
<span v-if='value.course.numenrolled != 1'>{{ value.course.numenrolled }} {{ text.students_from_plan_enrolled }}</span>
<span v-else> 1 {{ text.student_from_plan_enrolled }} </span>
</div>
</div> </div>
<div class="r-course-detail-header-right"> <div class="r-course-detail-header-right">
<div class="r-completion-detail-header"> <div class="r-completion-detail-header">

View File

@ -859,7 +859,7 @@ export default {
}, },
cohortOptionModel(c){ cohortOptionModel(c){
return { return {
value: c.id, val: c.id,
text: c.name + ' (' + c.context.path.join(' / ') + ')', text: c.name + ' (' + c.context.path.join(' / ') + ')',
}; };
}, },

File diff suppressed because one or more lines are too long

View File

@ -37,15 +37,21 @@ class completionscanner {
* @var array * @var array
*/ */
private static $modsupported = []; private static $modsupported = [];
/**
* Cache of enrolled students in a particular course
* @var array
*/
private static $coursestudents = [];
/** The internally used grading scanner /** The internally used grading scanner
* @var local\ungradedscanners\scanner_base * @var local\ungradedscanners\scanner_base
*/ */
private $scanner = null; private $scanner = null;
/** @var int */
private $courseid;
/** @var stdClass */
private $course;
/** @var \course_modinfo */
private $modinfo;
/** @var completion_criteria */
private $crit;
/** /**
* Course module * Course module
* @var \cm_info * @var \cm_info
@ -71,22 +77,14 @@ class completionscanner {
} }
/** /**
* List all users enrolled in a course as student by userid * Filter a list of students to return only the students enrolled as student
* @param int $courseid Course id of the course to check * in this scanner's course
* @return int[] Array if user ids * @param int[] $studentlist Array of student id's
* @return int[]
*/ */
public static function get_course_students($courseid) : array { private function filter_studentlist(array $studentlist) : array {
global $CFG; $course_students = courseinfo::get_course_students($this->courseid);
if (!array_key_exists($courseid, self::$coursestudents)) { return array_intersect($studentlist, $course_students);
$students = [];
$context = \context_course::instance($courseid);
foreach (explode(', ', $CFG->gradebookroles) as $roleid) {
$roleid = trim($roleid);
$students = array_keys(get_role_users($roleid, $context, false, 'u.id', 'u.id ASC'));
}
self::$coursestudents[$courseid] = $students;
}
return self::$coursestudents[$courseid];
} }
/** /**
@ -159,11 +157,16 @@ class completionscanner {
/** /**
* Webservice model for basic info * Webservice model for basic info
* @param int[]|null $studentlist Array of student userids to use for checking. Leave empty to use all course students
*/
public function model(array $studentlist = null) : array {
/*
If an array of students is provided (usually the case if called from a courecompletioninfo object),
make sure to filter it out, so only the students enrolled in the course are included.. Otherwise
statistics are marred.
*/ */
public function model() : array {
// Get completion info. // Get completion info.
$students = self::get_course_students($this->courseid); $students = isset($studentlist) ? $this->filter_studentlist($studentlist) : courseinfo::get_course_students($this->courseid);
$completed = 0; $completed = 0;
$ungraded = 0; $ungraded = 0;
$completedpass = 0; $completedpass = 0;

View File

@ -27,6 +27,7 @@ require_once($CFG->libdir.'/externallib.php');
require_once($CFG->libdir.'/gradelib.php'); require_once($CFG->libdir.'/gradelib.php');
require_once($CFG->dirroot.'/course/lib.php'); require_once($CFG->dirroot.'/course/lib.php');
use core\check\performance\debugging;
use core_course\local\repository\caching_content_item_readonly_repository; use core_course\local\repository\caching_content_item_readonly_repository;
use core_course\local\repository\content_item_readonly_repository; use core_course\local\repository\content_item_readonly_repository;
use \grade_item; use \grade_item;
@ -239,9 +240,10 @@ class corecompletioninfo {
/** /**
* Webservice model for editor info * Webservice model for editor info
* @param int[] $studentlist List of user id's to use for checking issueing progress within a study plan
* @return array Webservice data model * @return array Webservice data model
*/ */
public function editor_model() { public function editor_model(array $studentlist = null) {
global $DB, $CFG; global $DB, $CFG;
$conditions = []; $conditions = [];
@ -256,12 +258,12 @@ class corecompletioninfo {
if ($this->completion->is_enabled()) { if ($this->completion->is_enabled()) {
$aggregation = $this->completion->get_aggregation_method(); $aggregation = $this->completion->get_aggregation_method();
// Loop through all condition types to see if they are applicable. // Loop through all condition types to see if they are applicable.
foreach (self::completiontypes() as $type) { foreach (self::completiontypes() as $type => $handle) {
$criterias = $this->completion->get_criteria($type); // Returns array of relevant criteria items. $criterias = $this->completion->get_criteria($type); // Returns array of relevant criteria items.
if (count($criterias) > 0 ) { if (count($criterias) > 0 ) {
// Only take it into account if the criteria count is > 0. // Only take it into account if the criteria count is > 0.
$cinfo = [ $cinfo = [
"type" => self::completiontypes()[$type], "type" => $handle,
"aggregation" => self::aggregation_handle($this->completion->get_aggregation_method($type)), "aggregation" => self::aggregation_handle($this->completion->get_aggregation_method($type)),
"title" => reset($criterias)->get_type_title(), "title" => reset($criterias)->get_type_title(),
"items" => [], "items" => [],
@ -386,7 +388,7 @@ class corecompletioninfo {
"id" => $criteria->id, "id" => $criteria->id,
"title" => $criteria->get_title_detailed(), "title" => $criteria->get_title_detailed(),
"details" => $details, "details" => $details,
"progress" => $scanner->model(), "progress" => $scanner->model($studentlist),
]; ];
} }
@ -444,14 +446,14 @@ class corecompletioninfo {
if ($this->completion->is_enabled() && $this->completion->is_tracked_user($userid)) { if ($this->completion->is_enabled() && $this->completion->is_tracked_user($userid)) {
$anypending = false; $anypending = false;
// Loop through all conditions to see if they are applicable. // Loop through all conditions to see if they are applicable.
foreach (self::completiontypes() as $type) { foreach (self::completiontypes() as $type => $handle) {
// Get the main completion for this type. // Get the main completion for this type.
$completions = $this->completion->get_completions($userid, $type); $completions = $this->completion->get_completions($userid, $type);
if (count($completions) > 0) { if (count($completions) > 0) {
$typeaggregation = $this->completion->get_aggregation_method($type); $typeaggregation = $this->completion->get_aggregation_method($type);
$completed = $this->aggregate_completions($typeaggregation, $completions); $completed = $this->aggregate_completions($typeaggregation, $completions);
$cinfo = [ $cinfo = [
"type" => self::completiontypes()[$type], "type" => $handle,
"aggregation" => self::aggregation_handle($typeaggregation), "aggregation" => self::aggregation_handle($typeaggregation),
"completed" => $completed, "completed" => $completed,
"status" => $completed ? "complete" : "incomplete", "status" => $completed ? "complete" : "incomplete",
@ -619,73 +621,28 @@ class corecompletioninfo {
* Returns the percentage completed by a certain user, returns null if no completion data is available. * Returns the percentage completed by a certain user, returns null if no completion data is available.
* *
* @param int $userid The id of the user, 0 for the current user * @param int $userid The id of the user, 0 for the current user
* @return null|float The percentage, or null if completion is not supported in the course, * @return \stdClass The percentage info, left all 0 if completion is not supported in the course,
* or there are no activities that support completion. * or if there are no activities that support completion.
*/
public function get_progress_percentage($userid) {
// First, let's make sure completion is enabled.
if (!$this->completion->is_enabled()) {
return null;
}
if (!$this->completion->is_tracked_user($userid)) {
return null;
}
$completions = $this->completion->get_completions($userid);
$count = count($completions);
$completed = 0;
// Before we check how many modules have been completed see if the course has completed. .
if ($this->completion->is_course_complete($userid)) {
$completed = $count;
} else {
// Count all completions, but treat .
foreach ($completions as $completion) {
$crit = $completion->get_criteria();
if ($crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
// Get the cm data object.
$cm = $this->modinfo->get_cm($crit->moduleinstance);
// Retrieve data for this object.
$data = $this->completion->get_data($cm, false, $userid);
// Count complete, but failed as incomplete too...
if (($data->completionstate == COMPLETION_INCOMPLETE)
|| ($data->completionstate == COMPLETION_COMPLETE_FAIL)) {
$completed += 0;
} else {
$completed += 1;
}
} else {
if ($completion->is_complete()) {
$completed += 1;
}
}
}
}
$result = new \stdClass;
$result->count = $count;
$result->completed = $completed;
$result->percentage = ($completed / $count) * 100;
return $result;
}
/**
* Returns the percentage completed by a certain user, returns null if no completion data is available.
*
* @param int $userid The id of the user, 0 for the current user
* @return null|\stdClass The percentage, or null if completion is not supported in the course,
* or there are no activities that support completion.
*/ */
public function get_advanced_progress_percentage($userid): \stdClass { public function get_advanced_progress_percentage($userid): \stdClass {
// First, let's make sure completion is enabled. // First, let's make sure completion is enabled.
if (!$this->completion->is_enabled()) { if (!$this->completion->is_enabled()) {
return null; debugging("Completion is not enabled for {$this->course->shortname}",DEBUG_NORMAL);
return (object)[
'count' => 0,
'completed' => 0,
'percentage' => 0,
];
} }
if (!$this->completion->is_tracked_user($userid)) { if (!$this->completion->is_tracked_user($userid)) {
return null; debugging("$userid is not tracked in {$this->course->shortname}");
return (object)[
'count' => 0,
'completed' => 0,
'percentage' => 0,
];
} }
$completions = $this->completion->get_completions($userid); $completions = $this->completion->get_completions($userid);

View File

@ -52,7 +52,11 @@ class courseinfo {
private $studyitem; private $studyitem;
/** @var array */ /** @var array */
private static $contentitems = null; private static $contentitems = null;
/**
* Cache of enrolled students in a particular course
* @var array
*/
private static $coursestudents = [];
/** /**
* Return database identifier * Return database identifier
* @return int * @return int
@ -285,6 +289,7 @@ class courseinfo {
"amteacher" => new \external_value(PARAM_BOOL, 'Requesting user is teacher in this course'), "amteacher" => new \external_value(PARAM_BOOL, 'Requesting user is teacher in this course'),
"canupdatecourse" => new \external_value(PARAM_BOOL, "If the current user can update this course"), "canupdatecourse" => new \external_value(PARAM_BOOL, "If the current user can update this course"),
"canselectgradables" => new \external_value(PARAM_BOOL, 'Requesting user can change selected gradables'), "canselectgradables" => new \external_value(PARAM_BOOL, 'Requesting user can change selected gradables'),
"numenrolled" => new \external_value(PARAM_INT, 'number of students from this studyplan enrolled in the course'),
"tag" => new \external_value(PARAM_TEXT, 'Tag'), "tag" => new \external_value(PARAM_TEXT, 'Tag'),
], 'referenced course information', $value); ], 'referenced course information', $value);
} }
@ -301,6 +306,12 @@ class courseinfo {
$timing = $this->timing(); $timing = $this->timing();
if (isset($studyitem)) {
$numenrolled = $this->count_enrolled_students($studyitem->studyline()->studyplan()->find_linked_userids());
} else {
$numenrolled = 0;
}
$info = [ $info = [
'id' => $this->course->id, 'id' => $this->course->id,
'fullname' => $this->course->fullname, 'fullname' => $this->course->fullname,
@ -316,6 +327,7 @@ class courseinfo {
'canselectgradables' => $this->i_can_select_gradables(), 'canselectgradables' => $this->i_can_select_gradables(),
'tag' => "Editormodel", 'tag' => "Editormodel",
'grades' => [], 'grades' => [],
'numenrolled' => $numenrolled,
]; ];
if (!$usecorecompletioninfo) { if (!$usecorecompletioninfo) {
@ -324,9 +336,10 @@ class courseinfo {
foreach ($gradables as $gradable) { foreach ($gradables as $gradable) {
$info['grades'][] = $gradable->editor_model($studyitem ? $studyitem : $this->studyitem); $info['grades'][] = $gradable->editor_model($studyitem ? $studyitem : $this->studyitem);
} }
} else { } else if (isset($this->studyitem)) {
$cc = new corecompletioninfo($this->course); $cc = new corecompletioninfo($this->course, $this->studyitem);
$info['completion'] = $cc->editor_model(); $studentlist = $this->studyitem->studyline()->studyplan()->find_linked_userids();
$info['completion'] = $cc->editor_model($studentlist);
} }
return $info; return $info;
@ -349,9 +362,59 @@ class courseinfo {
"timing" => new \external_value(PARAM_TEXT, '(past|present|future)'), "timing" => new \external_value(PARAM_TEXT, '(past|present|future)'),
"startdate" => new \external_value(PARAM_TEXT, 'Course start date'), "startdate" => new \external_value(PARAM_TEXT, 'Course start date'),
"enddate" => new \external_value(PARAM_TEXT, 'Course end date'), "enddate" => new \external_value(PARAM_TEXT, 'Course end date'),
"enrolled" => new \external_value(PARAM_BOOL, 'True if student is enrolled as student in this course'),
], 'course information', $value); ], 'course information', $value);
} }
/**
* List all users enrolled in a course as student by userid
* @param int $courseid Course id of the course to check
* @return int[] Array if user ids
*/
public static function get_course_students($courseid) : array {
global $CFG;
if (!array_key_exists($courseid, self::$coursestudents)) {
$students = [];
$context = \context_course::instance($courseid);
foreach (explode(', ', $CFG->gradebookroles) as $roleid) {
$roleid = trim($roleid);
$students = array_keys(get_role_users($roleid, $context, false, 'u.id', 'u.id ASC'));
}
self::$coursestudents[$courseid] = $students;
}
return self::$coursestudents[$courseid];
}
/**
* Check if a user is enrolled as a student in this course
* (Has a gradebook role)
* @param int $userid The user Id to check
*/
public function is_enrolled_student($userid) : bool {
global $CFG;
foreach (explode(', ', $CFG->gradebookroles) as $roleid) {
if (user_has_role_assignment($userid, $roleid, $this->coursecontext->id)) {
return true;
}
}
return false;
}
/**
* List how many users from a list also enrolled as students
* (Has a gradebook role)
* @param int[] $userids The user Ids to check
*/
private function count_enrolled_students(array $userids) {
$count = 0;
foreach($userids as $userid){
if($this->is_enrolled_student($userid)){
$count++;
}
}
return $count;
}
/** /**
* Webservice model for user info * Webservice model for user info
* @param int $userid ID of user to check specific info for * @param int $userid ID of user to check specific info for
@ -375,6 +438,7 @@ class courseinfo {
'startdate' => date("Y-m-d", $this->course->startdate), 'startdate' => date("Y-m-d", $this->course->startdate),
'enddate' => date("Y-m-d", $this->course->enddate), 'enddate' => date("Y-m-d", $this->course->enddate),
'grades' => [], 'grades' => [],
'enrolled' => $this->is_enrolled_student($userid),
]; ];
if (!$usecorecompletioninfo) { if (!$usecorecompletioninfo) {
@ -382,8 +446,8 @@ class courseinfo {
foreach ($gradables as $gi) { foreach ($gradables as $gi) {
$info['grades'][] = $gi->user_model($userid); $info['grades'][] = $gi->user_model($userid);
} }
} else { } else if (isset($this->studyitem)) {
$cc = new corecompletioninfo($this->course); $cc = new corecompletioninfo($this->course,$this->studyitem);
$info['completion'] = $cc->user_model($userid); $info['completion'] = $cc->user_model($userid);
} }

View File

@ -448,18 +448,15 @@ class courseservice extends \external_api {
* @param mixed $courseid Id of course this cirteria is related to * @param mixed $courseid Id of course this cirteria is related to
* @return array * @return array
*/ */
public static function scan_completion_progress($criteriaid, $studyplanid, $courseid) { public static function scan_completion_progress($criteriaid, $studyitemid) {
global $DB; global $DB;
// Verify access to the study plan. // Verify access to the study plan.
$o = studyplan::find_by_id($studyplanid); $item = studyitem::find_by_id($studyitemid);
$o = $item->studyline()->studyplan();
webservicehelper::require_capabilities(self::CAP_VIEW, $o->context()); webservicehelper::require_capabilities(self::CAP_VIEW, $o->context());
$crit = \completion_criteria::fetch(["id" => $criteriaid]); $crit = \completion_criteria::fetch(["id" => $criteriaid]);
if (!$o->course_linked($courseid)) { $scanner = new completionscanner($crit, $studyitemid);
throw new \webservice_access_exception(
"Course {$courseid} linked to criteria {$criteriaid} is not linked to studyplan {$o->id()}");
}
$scanner = new completionscanner($crit, \get_course($courseid));
return $scanner->model(); return $scanner->model();
} }

View File

@ -73,7 +73,7 @@ class reportinvite_form extends moodleform {
/** /**
* Get supplied user data * Get supplied user data
* @return array The supplied data * @return stdClass The supplied data
*/ */
public function get_data() { public function get_data() {
global $DB, $USER; global $DB, $USER;

View File

@ -517,7 +517,7 @@ class studyitem {
/** /**
* Get courseinfo for studyitem if it references a course * Get courseinfo for studyitem if it references a course
*/ */
public function getcourseinfo() : courseinfo { public function getcourseinfo() : ?courseinfo {
if (empty($this->courseinfo) && courseinfo::exists($this->r->course_id)) { if (empty($this->courseinfo) && courseinfo::exists($this->r->course_id)) {
$this->courseinfo = new courseinfo($this->r->course_id, $this); $this->courseinfo = new courseinfo($this->r->course_id, $this);
} }

View File

@ -1104,6 +1104,10 @@
.features-treestudyplan .t-configured-alert { .features-treestudyplan .t-configured-alert {
color: var(--warning); color: var(--warning);
} }
.path-local-treestudyplan .t-not-enrolled-alert,
.features-treestudyplan .t-not-enrolled-alert {
color: var(--info);
}
.path-local-treestudyplan .r-grading-bar, .path-local-treestudyplan .r-grading-bar,
.features-treestudyplan .r-grading-bar { .features-treestudyplan .r-grading-bar {
display: inline-block; display: inline-block;

View File

@ -27,7 +27,9 @@ require_once($CFG->libdir.'/weblib.php');
$systemcontext = context_system::instance(); $systemcontext = context_system::instance();
$PAGE->set_url("/local/treestudyplan/doc.php", array()); $PAGE->set_url("/local/treestudyplan/doc.php", array());
if($CFG->debugdeveloper){
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
}
$PAGE->set_pagelayout('base'); $PAGE->set_pagelayout('base');
$PAGE->set_context($systemcontext); $PAGE->set_context($systemcontext);
require_login(); require_login();

View File

@ -75,7 +75,9 @@ if ($studyplancontext->id > 1) {
// Load javascripts and specific css. // Load javascripts and specific css.
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
if($CFG->debugdeveloper){
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
}
$PAGE->requires->js_call_amd('local_treestudyplan/page-edit-plan', 'init', [$studyplancontext->id, $categoryid]); $PAGE->requires->js_call_amd('local_treestudyplan/page-edit-plan', 'init', [$studyplancontext->id, $categoryid]);
$catlist = courseservice::list_accessible_categories_with_usage("edit"); $catlist = courseservice::list_accessible_categories_with_usage("edit");

View File

@ -65,7 +65,9 @@ if (empty($invite)) {
} else { } else {
// Load javascripts and specific css. // Load javascripts and specific css.
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
if($CFG->debugdeveloper){
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
}
$PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init', ['invited', $invitekey]); $PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init', ['invited', $invitekey]);
$student = $DB->get_record('user', array('id' => $invite->user_id)); $student = $DB->get_record('user', array('id' => $invite->user_id));

View File

@ -90,7 +90,7 @@ $string['settingdesc_display_heading'] = 'Study plan display settings';
$string['setting_display_field'] = 'Course display name'; $string['setting_display_field'] = 'Course display name';
$string['settingdesc_display_field'] = 'Select the field to use for the display name of a course in the studyplan'; $string['settingdesc_display_field'] = 'Select the field to use for the display name of a course in the studyplan';
$string['settingspage_csync'] = 'Studyplan cohort sync'; $string['settingspage_csync'] = 'Synchronize linked cohorts and users to courses';
$string['setting_csync_heading'] = 'Automatically create a cohort sync in all courses linked to a studyplan for all cohorts linked to a studyplan'; $string['setting_csync_heading'] = 'Automatically create a cohort sync in all courses linked to a studyplan for all cohorts linked to a studyplan';
$string['settingdesc_csync_heading'] = ''; $string['settingdesc_csync_heading'] = '';
$string['setting_csync_enable_field'] = 'Automatic cohort sync'; $string['setting_csync_enable_field'] = 'Automatic cohort sync';
@ -175,6 +175,11 @@ $string['completion_good'] = "Good";
$string['completion_excellent'] = "Excellent"; $string['completion_excellent'] = "Excellent";
$string['completion_passed'] = "Passed"; $string['completion_passed'] = "Passed";
$string["incomplete"] = 'Not started';
$string["completed"] = 'Completed';
$string["completed_pass"] = 'Passed';
$string["completed_fail"] = 'Failed';
$string['cfg_grades'] = 'Configure grade & scale interpretation'; $string['cfg_grades'] = 'Configure grade & scale interpretation';
$string['cfg_plans'] = 'Manage study plans'; $string['cfg_plans'] = 'Manage study plans';
$string['cfg_help'] = "Studyplan plugin documentation"; $string['cfg_help'] = "Studyplan plugin documentation";
@ -329,3 +334,9 @@ $string["course_timing_off"] = 'Course timing does not match period timing. Clic
$string["course_period_span"] = 'Spans'; $string["course_period_span"] = 'Spans';
$string["course_period_span_desc"] = 'If the space directly after this course is free, the course can be expanded to span multiple periods.'; $string["course_period_span_desc"] = 'If the space directly after this course is free, the course can be expanded to span multiple periods.';
$string["view_completion_report"] = 'View detailed course completion report'; $string["view_completion_report"] = 'View detailed course completion report';
$string["student_not_tracked"] = 'Not enrolled in this course';
$string["completion_not_enabled"] = 'Completion is not enabled in this course';
$string["student_from_plan_enrolled"] = 'student in this studyplan is enrolled in the course';
$string["students_from_plan_enrolled"] = 'students in this studyplan are enrolled in the course';
$string["not_enrolled"] = "Not enrolled";

View File

@ -92,7 +92,7 @@ $string['settingdesc_display_heading'] = 'Configuratie voor de weergave van de s
$string['setting_display_field'] = 'Weergavenaam cursus'; $string['setting_display_field'] = 'Weergavenaam cursus';
$string['settingdesc_display_field'] = 'Kies welk veld gebruikt moet worden als weergavenaam van een cursus'; $string['settingdesc_display_field'] = 'Kies welk veld gebruikt moet worden als weergavenaam van een cursus';
$string['settingspage_csync'] = 'Studieplan site-groep synchronisatie'; $string['settingspage_csync'] = 'Site-groepen en gebruikerskoppelingen doorzetten naar cursussen';
$string['setting_csync_heading'] = 'Site-groepen die aan een studieplan gekoppeld zijn automatisch als site-groep synchronisatie koppelen aan alle cursussen in het studieplan.'; $string['setting_csync_heading'] = 'Site-groepen die aan een studieplan gekoppeld zijn automatisch als site-groep synchronisatie koppelen aan alle cursussen in het studieplan.';
$string['settingdesc_csync_heading'] = ''; $string['settingdesc_csync_heading'] = '';
$string['setting_csync_enable_field'] = 'Automatisch koppelen inschakelen'; $string['setting_csync_enable_field'] = 'Automatisch koppelen inschakelen';
@ -177,6 +177,11 @@ $string['completion_good'] = "Goed";
$string['completion_excellent'] = "Uitstekend"; $string['completion_excellent'] = "Uitstekend";
$string['completion_passed'] = "Behaald"; $string['completion_passed'] = "Behaald";
$string["incomplete"] = 'Niet gestart';
$string["completed"] = 'Voltooid';
$string["completed_pass"] = 'Behaald';
$string["completed_fail"] = 'Onvoldoende';
$string['cfg_grades'] = 'Configureer betekenis van beoordelingen en schalen'; $string['cfg_grades'] = 'Configureer betekenis van beoordelingen en schalen';
$string['cfg_plans'] = 'Studieplannen beheren'; $string['cfg_plans'] = 'Studieplannen beheren';
$string['cfg_help'] = "Studieplan plugin documentatie (Engels)"; $string['cfg_help'] = "Studieplan plugin documentatie (Engels)";
@ -333,3 +338,9 @@ $string["course_timing_off"] = 'Cursustiming en periodetiming komen niet overeen
$string["course_period_span"] = 'Duurt'; $string["course_period_span"] = 'Duurt';
$string["course_period_span_desc"] = 'Als de ruimte na deze cursus leeg is, kan de cursus worden uitgespreid over meerdere perioden.'; $string["course_period_span_desc"] = 'Als de ruimte na deze cursus leeg is, kan de cursus worden uitgespreid over meerdere perioden.';
$string["view_completion_report"] = 'Bekijk gedetailleerd voltooingsoverzicht'; $string["view_completion_report"] = 'Bekijk gedetailleerd voltooingsoverzicht';
$string["student_not_tracked"] = 'Niet ingeschreven in deze cursus';
$string["completion_not_enabled"] = 'Cursusvoltooiing is niet ingeschakeld';
$string["student_from_plan_enrolled"] = 'student in dit studieplan is in deze cursus ingeschreven';
$string["students_from_plan_enrolled"] = 'studenten in dit studieplan zijn in deze cursus ingeschreven';
$string["not_enrolled"] = "Niet ingeschreven";

View File

@ -38,7 +38,9 @@ $PAGE->set_heading(get_string('report_invited', 'local_treestudyplan', "{$USER->
// Load javascripts and specific css. // Load javascripts and specific css.
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
if($CFG->debugdeveloper){
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
}
$PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init'); $PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init');

View File

@ -46,7 +46,9 @@ if ($teachermode) {
// Load javascripts and specific css. // Load javascripts and specific css.
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
if($CFG->debugdeveloper){
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
}
$PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init', [$teachermode ? 'teaching' : 'myreport']); $PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init', [$teachermode ? 'teaching' : 'myreport']);
/** /**

View File

@ -940,7 +940,9 @@
.t-configured-alert { .t-configured-alert {
color: var(--warning); color: var(--warning);
} }
.t-not-enrolled-alert {
color: var(--info);
}
.r-grading-bar { .r-grading-bar {
display: inline-block; display: inline-block;

View File

@ -1104,6 +1104,10 @@
.features-treestudyplan .t-configured-alert { .features-treestudyplan .t-configured-alert {
color: var(--warning); color: var(--warning);
} }
.path-local-treestudyplan .t-not-enrolled-alert,
.features-treestudyplan .t-not-enrolled-alert {
color: var(--info);
}
.path-local-treestudyplan .r-grading-bar, .path-local-treestudyplan .r-grading-bar,
.features-treestudyplan .r-grading-bar { .features-treestudyplan .r-grading-bar {
display: inline-block; display: inline-block;

View File

@ -22,7 +22,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
$plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494). $plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494).
$plugin->version = 2023082101; // YYYYMMDDHH (year, month, day, iteration). $plugin->version = 2023083100; // YYYYMMDDHH (year, month, day, iteration).
$plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11). $plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11).
$plugin->release = "1.0.0"; $plugin->release = "1.0.0";

View File

@ -75,7 +75,9 @@ if ($studyplancontext->id > 1) {
// Load javascripts and specific css. // Load javascripts and specific css.
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
if($CFG->debugdeveloper){
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css')); $PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
}
$PAGE->requires->js_call_amd('local_treestudyplan/page-view-plan', 'init', [$studyplancontext->id, $categoryid]); $PAGE->requires->js_call_amd('local_treestudyplan/page-view-plan', 'init', [$studyplancontext->id, $categoryid]);
/** /**