Implemented coach view
This commit is contained in:
parent
6bb13de5cf
commit
7dbcb437c3
2
amd/build/page-coach.min.js
vendored
2
amd/build/page-coach.min.js
vendored
|
@ -1,3 +1,3 @@
|
|||
define("local_treestudyplan/page-coach",["exports","core/ajax","core/notification","./vue/vue","./util/debugger","./util/string-helper","./studyplan-processor","./util/date-helper","./report-viewer-components","./treestudyplan-components","./modedit-modal","./portal-vue/portal-vue.esm","./bootstrap-vue/bootstrap-vue"],(function(_exports,_ajax,_notification,_vue,_debugger,_stringHelper,_studyplanProcessor,_dateHelper,_reportViewerComponents,_treestudyplanComponents,_modeditModal,_portalVue,_bootstrapVue){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){let app=new _vue.default({el:"#root",data:{displayedstudyplan:null,activestudyplan:null,associatedstudents:[],selectedstudent:null,studentstudyplan:null,loadingstudyplan:!1,studyplans:[],text:strings.studyplan,toolbox:{right:!0},usedcontexts:[]},async mounted(){(0,_ajax.call)([{methodname:"list_coaching_studyplans",args:{}}])[0].then((function(response){const timingval={present:0,past:1,future:2};response.sort(((a,b)=>{const timinga=(0,_dateHelper.studyplanTiming)(a),timingb=(0,_dateHelper.studyplanTiming)(b),t=timingval[timinga]-timingval[timingb];return 0==t?a.name.localeCompare(b.name):t})),app.studyplans=response;const parts=window.location.hash.replace("#","").split("-");if(parts&&parts.length>0)for(let idx in app.studyplans)if(app.studyplans[idx].id==parts[0]){app.selectStudyplan(app.studyplans[idx],parts[1]);break}})).catch(_notification.default.exception)},computed:{},methods:{closeStudyplan(){app.activestudyplan=null,app.associatedstudents=[],app.studentstudyplan=[],app.displayedstudyplan=null,window.location.hash=""},selectStudyplan(studyplan,studentid){app.loadingstudyplan=!0,app.activestudyplan=null,app.associatedstudents=[],app.selectedstudent=null,app.studentstudyplan=null,(0,_ajax.call)([{methodname:"local_treestudyplan_get_studyplan_map",args:{id:studyplan.id}}])[0].then((function(response){app.activestudyplan=(0,_studyplanProcessor.ProcessStudyplan)(response,!0),app.displayedstudyplan=app.activestudyplan,app.loadingstudyplan=!1,window.location.hash=app.activestudyplan.id,(0,_ajax.call)([{methodname:"local_treestudyplan_all_associated_grouped",args:{studyplan_id:studyplan.id}}])[0].then((function(response){if(app.associatedstudents=response,studentid)for(const group of app.associatedstudents)for(const student of group.users)if(student.id==studentid){app.showStudentView(student);break}})).catch(_notification.default.exception)})).catch((function(error){_notification.default.exception(error),app.loadingstudyplan=!1}))},showStudentView(student){app.selectedstudent=student,app.studentstudyplan=null,student&&(app.loadingstudyplan=!0,(0,_ajax.call)([{methodname:"local_treestudyplan_get_user_studyplan",args:{userid:student.id,studyplanid:app.activestudyplan.id}}])[0].then((function(response){app.studentstudyplan=(0,_studyplanProcessor.ProcessStudyplan)(response,!1),app.displayedstudyplan=app.studentstudyplan,app.loadingstudyplan=!1,window.location.hash=app.activestudyplan.id+"-"+student.id})).catch((function(error){_notification.default.exception(error),app.loadingstudyplan=!1})))},showOverview(){app.selectedstudent=null,app.studentstudyplan=null,app.displayedstudyplan=app.activestudyplan,window.location.hash=app.activestudyplan.id}}})},_notification=_interopRequireDefault(_notification),_vue=_interopRequireDefault(_vue),_debugger=_interopRequireDefault(_debugger),_reportViewerComponents=_interopRequireDefault(_reportViewerComponents),_treestudyplanComponents=_interopRequireDefault(_treestudyplanComponents),_modeditModal=_interopRequireDefault(_modeditModal),_portalVue=_interopRequireDefault(_portalVue),_bootstrapVue=_interopRequireDefault(_bootstrapVue),_vue.default.use(_reportViewerComponents.default),_vue.default.use(_modeditModal.default),_vue.default.use(_portalVue.default),_vue.default.use(_bootstrapVue.default);new _debugger.default("treestudyplanviewer");let strings=(0,_stringHelper.load_strings)({studyplan:{studyplan_select_placeholder:"studyplan_select_placeholder"}})}));
|
||||
define("local_treestudyplan/page-coach",["exports","core/ajax","core/notification","./vue/vue","./util/debugger","./util/string-helper","./studyplan-processor","./util/date-helper","./studyplan-editor-components","./treestudyplan-components","./report-viewer-components","./modedit-modal","./portal-vue/portal-vue.esm","./bootstrap-vue/bootstrap-vue"],(function(_exports,_ajax,_notification,_vue,_debugger,_stringHelper,_studyplanProcessor,_dateHelper,_studyplanEditorComponents,_treestudyplanComponents,_reportViewerComponents,_modeditModal,_portalVue,_bootstrapVue){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){let app=new _vue.default({el:"#root",data:{displayedstudyplan:null,activestudyplan:null,associatedstudents:[],selectedstudent:null,studentstudyplan:null,loadingstudyplan:!1,studyplans:[],text:strings.coach,toolbox:{right:!0},usedcontexts:[],editmode:!1},async mounted(){(0,_ajax.call)([{methodname:"local_treestudyplan_list_coaching_studyplans",args:{}}])[0].then((function(response){const timingval={present:0,past:1,future:2};response.sort(((a,b)=>{const timinga=(0,_dateHelper.studyplanTiming)(a),timingb=(0,_dateHelper.studyplanTiming)(b),t=timingval[timinga]-timingval[timingb];return 0==t?a.name.localeCompare(b.name):t})),app.studyplans=response;const parts=window.location.hash.replace("#","").split("-");if(parts&&parts.length>0)for(let idx in app.studyplans)if(app.studyplans[idx].id==parts[0]){app.selectStudyplan(app.studyplans[idx],parts[1]);break}})).catch(_notification.default.exception)},computed:{},methods:{closeStudyplan(){app.activestudyplan=null,app.associatedstudents=[],app.studentstudyplan=[],app.displayedstudyplan=null,window.location.hash=""},selectStudyplan(studyplan,studentid){const self=this;self.loadingstudyplan=!0,self.activestudyplan=null,self.associatedstudents=[],self.selectedstudent=null,self.studentstudyplan=null,(0,_ajax.call)([{methodname:"local_treestudyplan_get_studyplan_map",args:{id:studyplan.id}}])[0].then((function(response){self.activestudyplan=(0,_studyplanProcessor.ProcessStudyplan)(response,!0),self.displayedstudyplan=self.activestudyplan,self.loadingstudyplan=!1,window.location.hash=self.activestudyplan.id,(0,_ajax.call)([{methodname:"local_treestudyplan_all_associated_grouped",args:{studyplan_id:studyplan.id}}])[0].then((function(response){if(self.associatedstudents=response,studentid){for(const group of self.associatedstudents)for(const student of group.users)if(student.id==studentid){self.showStudentView(student);break}}else for(const group of self.associatedstudents)for(const student of group.users){self.showStudentView(student);break}})).catch(_notification.default.exception)})).catch((function(error){_notification.default.exception(error),app.loadingstudyplan=!1}))},showStudentView(student){app.selectedstudent=student,app.studentstudyplan=null,student&&(app.loadingstudyplan=!0,(0,_ajax.call)([{methodname:"local_treestudyplan_get_user_studyplan",args:{userid:student.id,studyplanid:app.activestudyplan.id}}])[0].then((function(response){app.studentstudyplan=(0,_studyplanProcessor.ProcessStudyplan)(response,!1),app.displayedstudyplan=app.studentstudyplan,app.loadingstudyplan=!1,window.location.hash=app.activestudyplan.id+"-"+student.id})).catch((function(error){_notification.default.exception(error),app.loadingstudyplan=!1})))},showOverview(){app.selectedstudent=null,app.studentstudyplan=null,app.displayedstudyplan=app.activestudyplan,window.location.hash=app.activestudyplan.id}}})},_notification=_interopRequireDefault(_notification),_vue=_interopRequireDefault(_vue),_debugger=_interopRequireDefault(_debugger),_studyplanEditorComponents=_interopRequireDefault(_studyplanEditorComponents),_treestudyplanComponents=_interopRequireDefault(_treestudyplanComponents),_reportViewerComponents=_interopRequireDefault(_reportViewerComponents),_modeditModal=_interopRequireDefault(_modeditModal),_portalVue=_interopRequireDefault(_portalVue),_bootstrapVue=_interopRequireDefault(_bootstrapVue),_vue.default.use(_studyplanEditorComponents.default),_vue.default.use(_treestudyplanComponents.default),_vue.default.use(_reportViewerComponents.default),_vue.default.use(_modeditModal.default),_vue.default.use(_portalVue.default),_vue.default.use(_bootstrapVue.default);new _debugger.default("treestudyplancoach");let strings=(0,_stringHelper.load_strings)({coach:{studyplan_select_placeholder:"studyplan_select_placeholder",switch_coach_editmode:"switch_coach_editmode"}})}));
|
||||
|
||||
//# sourceMappingURL=page-coach.min.js.map
|
File diff suppressed because one or more lines are too long
2
amd/build/page-edit-plan.min.js
vendored
2
amd/build/page-edit-plan.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/report-viewer-components.min.js
vendored
2
amd/build/report-viewer-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/studyplan-editor-components.min.js
vendored
2
amd/build/studyplan-editor-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -16,9 +16,15 @@ import {load_strings} from './util/string-helper';
|
|||
import {ProcessStudyplan} from './studyplan-processor';
|
||||
import {studyplanTiming} from './util/date-helper';
|
||||
|
||||
import EditorComponents from './studyplan-editor-components';
|
||||
Vue.use(EditorComponents);
|
||||
|
||||
import TSComponents from './treestudyplan-components';
|
||||
Vue.use(TSComponents);
|
||||
|
||||
import RVComponents from './report-viewer-components';
|
||||
Vue.use(RVComponents);
|
||||
import TSComponents from './treestudyplan-components';
|
||||
|
||||
import ModalComponents from './modedit-modal';
|
||||
Vue.use(ModalComponents);
|
||||
|
||||
|
@ -28,11 +34,12 @@ import BootstrapVue from './bootstrap-vue/bootstrap-vue';
|
|||
Vue.use(BootstrapVue);
|
||||
|
||||
|
||||
let debug = new Debugger("treestudyplanviewer");
|
||||
let debug = new Debugger("treestudyplancoach");
|
||||
|
||||
let strings = load_strings({
|
||||
studyplan: {
|
||||
coach: {
|
||||
studyplan_select_placeholder: 'studyplan_select_placeholder',
|
||||
switch_coach_editmode: 'switch_coach_editmode',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -50,15 +57,16 @@ export function init() {
|
|||
studentstudyplan: null,
|
||||
loadingstudyplan: false,
|
||||
studyplans: [],
|
||||
text: strings.studyplan,
|
||||
text: strings.coach,
|
||||
toolbox: {
|
||||
right: true,
|
||||
},
|
||||
usedcontexts: [],
|
||||
editmode: false,
|
||||
},
|
||||
async mounted() {
|
||||
call([{
|
||||
methodname: 'list_coaching_studyplans',
|
||||
methodname: 'local_treestudyplan_list_coaching_studyplans',
|
||||
args: {}
|
||||
}])[0].then(function(response){
|
||||
const timingval = { present: 0, past: 1, future: 2};
|
||||
|
@ -103,33 +111,42 @@ export function init() {
|
|||
|
||||
selectStudyplan(studyplan,studentid){
|
||||
// fetch studyplan
|
||||
app.loadingstudyplan = true;
|
||||
app.activestudyplan = null;
|
||||
app.associatedstudents = [];
|
||||
app.selectedstudent = null;
|
||||
app.studentstudyplan = null;
|
||||
const self = this;
|
||||
self.loadingstudyplan = true;
|
||||
self.activestudyplan = null;
|
||||
self.associatedstudents = [];
|
||||
self.selectedstudent = null;
|
||||
self.studentstudyplan = null;
|
||||
call([{
|
||||
methodname: 'local_treestudyplan_get_studyplan_map',
|
||||
args: { id: studyplan.id}
|
||||
}])[0].then(function(response){
|
||||
app.activestudyplan = ProcessStudyplan(response,true);
|
||||
app.displayedstudyplan = app.activestudyplan;
|
||||
app.loadingstudyplan = false;
|
||||
window.location.hash = app.activestudyplan.id;
|
||||
self.activestudyplan = ProcessStudyplan(response,true);
|
||||
self.displayedstudyplan = self.activestudyplan;
|
||||
self.loadingstudyplan = false;
|
||||
window.location.hash = self.activestudyplan.id;
|
||||
call([{
|
||||
methodname: 'local_treestudyplan_all_associated_grouped',
|
||||
args: { studyplan_id: studyplan.id}
|
||||
}])[0].then(function(response){
|
||||
app.associatedstudents = response;
|
||||
self.associatedstudents = response;
|
||||
if(studentid){
|
||||
for(const group of app.associatedstudents) {
|
||||
for(const group of self.associatedstudents) {
|
||||
for(const student of group.users){
|
||||
if(student.id == studentid){
|
||||
app.showStudentView(student);
|
||||
self.showStudentView(student);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Select first student available.
|
||||
for(const group of self.associatedstudents) {
|
||||
for(const student of group.users){
|
||||
self.showStudentView(student);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).catch(notification.exception);
|
||||
|
||||
|
|
|
@ -11,10 +11,8 @@ import {call} from 'core/ajax';
|
|||
import notification from 'core/notification';
|
||||
import {resetAllFormDirtyStates} from 'core_form/changechecker';
|
||||
|
||||
|
||||
import Vue from './vue/vue';
|
||||
|
||||
|
||||
import EditorComponents from './studyplan-editor-components';
|
||||
Vue.use(EditorComponents);
|
||||
|
||||
|
@ -35,10 +33,6 @@ Vue.use(PortalVue);
|
|||
import BootstrapVue from './bootstrap-vue/bootstrap-vue';
|
||||
Vue.use(BootstrapVue);
|
||||
|
||||
import {Drag, Drop, DropList} from './vue-easy-dnd/vue-easy-dnd.esm';
|
||||
Vue.component('drag',Drag);
|
||||
Vue.component('drop',Drop);
|
||||
Vue.component('drop-list',DropList);
|
||||
|
||||
const debug = new Debugger("treestudyplan");
|
||||
|
||||
|
|
|
@ -539,6 +539,10 @@ export default {
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
coaching: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -704,7 +708,7 @@ export default {
|
|||
<!-- First paint the headings-->
|
||||
<div class='r-studyplan-headings'
|
||||
><s-studyline-header-heading :identifier="Number(page.id)"
|
||||
><a v-if="teachermode && selectedpage" class="ml-2"
|
||||
><a v-if="teachermode && selectedpage && !coaching" class="ml-2"
|
||||
:href="wwwroot+'//local/treestudyplan/result-overview.php?page='+selectedpage.id"
|
||||
|
||||
target='_blank'><i class='fa fa-list-ul'></i> {{text.overview}}</a
|
||||
|
@ -731,7 +735,7 @@ export default {
|
|||
v-if="index > 0"
|
||||
v-model="page.perioddesc[index-1]"
|
||||
:identifier="Number(page.id)"
|
||||
><a v-if="teachermode && selectedpage"
|
||||
><a v-if="teachermode && selectedpage && !coaching"
|
||||
v-b-tooltip.hover
|
||||
:href="wwwroot+'//local/treestudyplan/result-overview.php?page='+selectedpage.id
|
||||
+'&firstperiod='+index+'&lastperiod='+index"
|
||||
|
|
|
@ -23,6 +23,9 @@ import { premiumenabled, premiumstatus } from "./util/premium";
|
|||
import TSComponents from './treestudyplan-components';
|
||||
import mFormComponents from "./util/mform-helper";
|
||||
|
||||
import {Drag, Drop, DropList} from './vue-easy-dnd/vue-easy-dnd.esm';
|
||||
|
||||
|
||||
|
||||
const STUDYPLAN_EDITOR_FIELDS =
|
||||
['name','shortname','description','idnumber','context_id', 'aggregation','aggregation_config'];
|
||||
|
@ -41,10 +44,12 @@ const datechanger_globals = {
|
|||
export default {
|
||||
STUDYPLAN_EDITOR_FIELDS: STUDYPLAN_EDITOR_FIELDS, // make copy available in plugin
|
||||
install(Vue/*,options*/){
|
||||
Vue.component('drag',Drag);
|
||||
Vue.component('drop',Drop);
|
||||
Vue.component('drop-list',DropList);
|
||||
Vue.use(TSComponents);
|
||||
Vue.use(mFormComponents);
|
||||
let debug = new Debugger("treestudyplan-editor");
|
||||
debug.info("config",Config);
|
||||
/************************************
|
||||
* *
|
||||
* Treestudyplan Editor components *
|
||||
|
@ -1452,7 +1457,8 @@ export default {
|
|||
this.edit.studyline.editmode = true;
|
||||
}
|
||||
|
||||
// Retrieve available roles
|
||||
if (!self.coaching) {
|
||||
// Retrieve available roles (only needed as manager)
|
||||
call([{
|
||||
methodname: 'local_treestudyplan_list_roles',
|
||||
args: {
|
||||
|
@ -1461,7 +1467,7 @@ export default {
|
|||
}])[0].then(function(response){
|
||||
self.availableroles = response;
|
||||
}).catch(notification.exception);
|
||||
|
||||
}
|
||||
this.$root.$emit('redrawLines');
|
||||
this.$emit('pagechanged',this.selectedpage);
|
||||
},
|
||||
|
@ -1971,6 +1977,7 @@ export default {
|
|||
<b-form-select-option
|
||||
v-for="(nr,n) in 4"
|
||||
:value="n"
|
||||
:key="n"
|
||||
>{{text['line_enrollable_'+n]}}</b-form-select-option>
|
||||
</b-form-select>
|
||||
</b-col>
|
||||
|
@ -4147,7 +4154,7 @@ export default {
|
|||
type: Object,
|
||||
default() { return null;}
|
||||
},
|
||||
'coaching': {
|
||||
coaching: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
@ -4197,6 +4204,7 @@ export default {
|
|||
self.loadingcourses = false;
|
||||
}).catch(notification.exception);
|
||||
this.filter_systembadges();
|
||||
this.filter_relatedbadges();
|
||||
},
|
||||
filter_systembadges() {
|
||||
const self = this;
|
||||
|
|
|
@ -475,7 +475,11 @@ class associationservice extends \external_api {
|
|||
public static function associated_users($studyplanid) {
|
||||
global $CFG, $DB;
|
||||
$studyplan = studyplan::find_by_id($studyplanid);
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_VIEW, $studyplan->context());
|
||||
}
|
||||
|
||||
$sql = "SELECT DISTINCT u.* FROM {user} u INNER JOIN {local_treestudyplan_user} j ON j.user_id = u.id
|
||||
WHERE j.studyplan_id = :studyplan_id
|
||||
|
@ -614,7 +618,11 @@ class associationservice extends \external_api {
|
|||
global $CFG, $DB;
|
||||
|
||||
$studyplan = studyplan::find_by_id($studyplanid);
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_VIEW, $studyplan->context());
|
||||
}
|
||||
|
||||
$userlist = [
|
||||
[
|
||||
|
|
|
@ -212,7 +212,7 @@ class studyplanpage_editform extends formbase {
|
|||
$customdata->editoroptions,
|
||||
\context_system::instance(),
|
||||
'local_treestudyplan',
|
||||
'studyplan',
|
||||
'studyplanpage',
|
||||
$page->id());
|
||||
// Update the description
|
||||
$page->edit([
|
||||
|
|
|
@ -400,4 +400,13 @@ Klc5I28bGbvxIV5pnL6ZSjHEDp2WreM8HB0XFJwU+Q==
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an error if premium status is not enabled
|
||||
*/
|
||||
public static function require_premium($message="premiumfeature:warning") {
|
||||
if (! self::enabled()) {
|
||||
throw new \moodle_exception($message,"local_treestudyplan");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -119,7 +119,11 @@ class studentstudyplanservice extends \external_api {
|
|||
global $CFG, $DB;
|
||||
|
||||
$studyplan = studyplan::find_by_id($studyplanid);
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_VIEWOTHER, $studyplan->context());
|
||||
}
|
||||
|
||||
if ($studyplan->exist_for_user($userid)) {
|
||||
|
||||
|
@ -547,11 +551,11 @@ class studentstudyplanservice extends \external_api {
|
|||
|
||||
\external_api::validate_context(\context_system::instance());
|
||||
|
||||
$studyplanids = $DB->get_records("local_treestudyplan_coach",["user_id" => $userid]);
|
||||
$records = $DB->get_records("local_treestudyplan_coach",["user_id" => $userid]);
|
||||
|
||||
$list = [];
|
||||
foreach ($studyplanids as $id) {
|
||||
$studyplan = studyplan::find_by_id($id);
|
||||
foreach ($records as $r) {
|
||||
$studyplan = studyplan::find_by_id($r->studyplan_id);
|
||||
if (has_capability(self::CAP_COACH,$studyplan->context(),$USER)) {
|
||||
$list[] = $studyplan->simple_model($userid);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ class studyplan {
|
|||
|
||||
/** @var string */
|
||||
const TABLE = "local_treestudyplan";
|
||||
/** @var string */
|
||||
const TABLE_COACH = "local_treestudyplan_coach";
|
||||
|
||||
|
||||
/**
|
||||
* Cache retrieved studyitems in this session
|
||||
|
@ -606,6 +609,28 @@ class studyplan {
|
|||
}
|
||||
}
|
||||
|
||||
/** Check if this studyplan is linked to a particular user
|
||||
* @param bool|stdClass|null $user The userid or user record of the user Leave empty to check current user.
|
||||
*/
|
||||
public function is_coach($user=null) {
|
||||
global $DB, $USER;
|
||||
if($user == null) {
|
||||
$user = $USER;
|
||||
$userid = $USER->id;
|
||||
} else if (is_numeric($user)) {
|
||||
$userid = intval($user);
|
||||
} else {
|
||||
$userid = $user->id;
|
||||
}
|
||||
$r = $DB->get_record(self::TABLE_COACH,["studyplan_id" => $this->id, "user_id"=> $userid]);
|
||||
|
||||
if ($r && has_capability(associationservice::CAP_COACH,$this->context(),$userid)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Webservice structure for userinfo
|
||||
* @param int $value Webservice requirement constant
|
||||
|
|
|
@ -46,6 +46,11 @@ class studyplanservice extends \external_api {
|
|||
* @var string
|
||||
*/
|
||||
const CAP_VIEW = "local/treestudyplan:viewuserreports";
|
||||
/**
|
||||
* Capability required to view studyplans (for other users)
|
||||
* @var string
|
||||
*/
|
||||
const CAP_COACH = "local/treestudyplan:coach";
|
||||
|
||||
/************************
|
||||
* *
|
||||
|
@ -121,7 +126,13 @@ class studyplanservice extends \external_api {
|
|||
public static function get_studyplan_map($id) {
|
||||
if (isset($id) && $id > 0) {
|
||||
$studyplan = studyplan::find_by_id($id);
|
||||
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities([self::CAP_EDIT, self::CAP_VIEW], $studyplan->context());
|
||||
}
|
||||
|
||||
$model = $studyplan->editor_model();
|
||||
debug::dump($model);
|
||||
return $model;
|
||||
|
@ -281,9 +292,10 @@ class studyplanservice extends \external_api {
|
|||
$enddate, $aggregation = "bistate", $aggregationconfig = '', $contextid = 0) {
|
||||
// Validate access in the intended context.
|
||||
$context = webservicehelper::find_context($contextid);
|
||||
// Do not validate the context in this case, just check the permissions.
|
||||
// Do not validate the context in this case, just check the permissions in the specified context.
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $context, false);
|
||||
|
||||
// Also check the permissions in the context of the studyplan, in case it is not the same.
|
||||
$o = studyplan::find_by_id($id);
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $o->context());
|
||||
|
||||
|
@ -621,7 +633,13 @@ class studyplanservice extends \external_api {
|
|||
* @return array
|
||||
*/
|
||||
public static function add_studyitem($lineid, $type, $details, $slot = -1, $layer = 0) {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, studyline::find_by_id($lineid)->context());
|
||||
$line = studyline::find_by_id($lineid);
|
||||
$studyplan = $line->studyplan();
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context());
|
||||
}
|
||||
|
||||
$o = studyitem::add([
|
||||
'line_id' => $lineid,
|
||||
|
@ -670,7 +688,12 @@ class studyplanservice extends \external_api {
|
|||
public static function edit_studyitem($id, $conditions, $continuationid = false) {
|
||||
|
||||
$o = studyitem::find_by_id($id);
|
||||
$studyplan = $o->studyline()->studyplan();
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $o->context());
|
||||
}
|
||||
|
||||
$config = [
|
||||
'conditions' => $conditions,
|
||||
|
@ -721,7 +744,14 @@ class studyplanservice extends \external_api {
|
|||
public static function reorder_studyitems($resequence) {
|
||||
// Check for permissions to modify the studyplan.
|
||||
foreach ($resequence as $sq) {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, studyitem::find_by_id(($sq['id']))->context());
|
||||
$item = studyitem::find_by_id(($sq['id']));
|
||||
$studyplan = $item->studyline()->studyplan();
|
||||
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context());
|
||||
}
|
||||
}
|
||||
|
||||
return studyitem::reorder($resequence)->model();
|
||||
|
@ -756,7 +786,12 @@ class studyplanservice extends \external_api {
|
|||
*/
|
||||
public static function delete_studyitem($id) {
|
||||
$o = studyitem::find_by_id($id);
|
||||
$studyplan = $o->studyline()->studyplan();
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $o->context());
|
||||
}
|
||||
|
||||
return $o->delete()->model();
|
||||
}
|
||||
|
@ -792,8 +827,16 @@ class studyplanservice extends \external_api {
|
|||
*/
|
||||
public static function connect_studyitems($fromid, $toid) {
|
||||
// Validate permissions.
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, studyitem::find_by_id($fromid)->context());
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, studyitem::find_by_id($toid)->context());
|
||||
$studyplan = studyitem::find_by_id($fromid)->studyline()->studyplan();
|
||||
$toplan = studyitem::find_by_id($toid)->studyline()->studyplan();
|
||||
if ($toplan->id() != $studyplan->id()) {
|
||||
throw new \webservice_access_exception("The items to connect need to be in the same studyplan" );
|
||||
}
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context());
|
||||
}
|
||||
|
||||
$o = studyitemconnection::connect($fromid, $toid);
|
||||
return $o->model();
|
||||
|
@ -830,8 +873,19 @@ class studyplanservice extends \external_api {
|
|||
*/
|
||||
public static function disconnect_studyitems($fromid, $toid) {
|
||||
// Validate permissions.
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, studyitem::find_by_id($fromid)->context());
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, studyitem::find_by_id($toid)->context());
|
||||
$studyplan = studyitem::find_by_id($fromid)->studyline()->studyplan();
|
||||
$toplan = studyitem::find_by_id($toid)->studyline()->studyplan();
|
||||
if ($toplan->id() != $studyplan->id()) {
|
||||
throw new \webservice_access_exception("The items to connect need to be in the same studyplan" );
|
||||
}
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context());
|
||||
}
|
||||
|
||||
|
||||
|
||||
return studyitemconnection::disconnect($fromid, $toid)->model();
|
||||
}
|
||||
|
||||
|
@ -946,7 +1000,12 @@ class studyplanservice extends \external_api {
|
|||
|
||||
$results = [];
|
||||
$page = studyplanpage::find_by_id(($pageid));
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT,$page->studyplan()->context());
|
||||
$studyplan = $page->studyplan();
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context());
|
||||
}
|
||||
$badges = badgeinfo::find_page_related_badges($page,$search,$active,$includecoursebadges);
|
||||
|
||||
foreach ($badges as $badgeinfo) {
|
||||
|
@ -996,10 +1055,11 @@ class studyplanservice extends \external_api {
|
|||
// Find related course and course context.
|
||||
$coursecontext = gradeinfo::get_coursecontext_by_id($gradeid);
|
||||
// Do sanity checks.
|
||||
\external_api::validate_context($coursecontext);
|
||||
|
||||
$studyplan = studyitem::find_by_id($itemid)->studyline()->studyplan();
|
||||
\external_api::validate_context($studyplan->context());
|
||||
// Check correct capabilities.
|
||||
if (has_capability('local/treestudyplan:editstudyplan', studyitem::find_by_id($itemid)->context()) ||
|
||||
if ($studyplan->is_coach() || has_capability(self::CAP_EDIT, $studyplan->context()) ||
|
||||
is_enrolled($coursecontext, $USER, 'local/treestudyplan:selectowngradables')) {
|
||||
return gradeinfo::include_grade($gradeid, $itemid, $include, $required)->model();
|
||||
} else {
|
||||
|
@ -1044,18 +1104,17 @@ class studyplanservice extends \external_api {
|
|||
public static function require_competency($competencyid, $itemid, $required) {
|
||||
global $USER;
|
||||
$item = studyitem::find_by_id($itemid);
|
||||
\external_api::validate_context($item->context());
|
||||
// Find related course and course context.
|
||||
if($item->courseid()) {
|
||||
$coursecontext = \context_course::instance($item->courseid());
|
||||
// Do sanity checks.
|
||||
\external_api::validate_context($coursecontext);
|
||||
} else {
|
||||
$coursecontext = null;
|
||||
\external_api::validate_context($item->context());
|
||||
}
|
||||
|
||||
// Check correct capabilities.
|
||||
if (has_capability('local/treestudyplan:editstudyplan', $item->context()) ||
|
||||
$studyplan = $item->studyline()->studyplan();
|
||||
if ($studyplan->is_coach() || has_capability('local/treestudyplan:editstudyplan', $studyplan->context()) ||
|
||||
($coursecontext && is_enrolled($coursecontext, $USER, 'local/treestudyplan:selectowngradables'))) {
|
||||
return coursecompetencyinfo::require_competency($competencyid, $itemid, $required)->model();
|
||||
} else {
|
||||
|
@ -1781,7 +1840,12 @@ class studyplanservice extends \external_api {
|
|||
*/
|
||||
public static function set_studyitem_span($id, $span = null) {
|
||||
$o = studyitem::find_by_id($id);
|
||||
$studyplan = $o->studyline()->studyplan();
|
||||
if ($studyplan->is_coach()) {
|
||||
\external_api::validate_context($studyplan->context());
|
||||
} else {
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $o->context());
|
||||
}
|
||||
|
||||
$config = [ 'span' => $span];
|
||||
$o->edit($config);
|
||||
|
|
24
coach.php
24
coach.php
|
@ -22,23 +22,24 @@
|
|||
|
||||
require_once("../../config.php");
|
||||
|
||||
use local_treestudyplan\contextinfo;
|
||||
use \local_treestudyplan\courseservice;
|
||||
use \local_treestudyplan\premium;
|
||||
|
||||
require_once($CFG->libdir.'/weblib.php');
|
||||
|
||||
$systemcontext = context_system::instance();
|
||||
|
||||
$PAGE->set_url("/local/treestudyplan/view-plan.php", array());
|
||||
$PAGE->set_url("/local/treestudyplan/coach.php", array());
|
||||
require_login();
|
||||
|
||||
|
||||
$PAGE->set_pagelayout('base');
|
||||
//$PAGE->set_context($studyplancontext);
|
||||
$PAGE->set_title(get_string('coaching_plans', 'local_treestudyplan')." - ".$contextname);
|
||||
$PAGE->set_heading(get_string('coaching_plans', 'local_treestudyplan')." - ".$contextname);
|
||||
$PAGE->set_context($systemcontext);
|
||||
$PAGE->set_title(get_string('coaching_plans', 'local_treestudyplan'));
|
||||
$PAGE->set_heading(get_string('coaching_plans', 'local_treestudyplan'));
|
||||
|
||||
|
||||
premium::require_premium();
|
||||
|
||||
|
||||
// Load javascripts and specific css.
|
||||
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
|
||||
|
@ -93,7 +94,7 @@ print $OUTPUT->header();
|
|||
variant="primary"
|
||||
>
|
||||
<template v-slot="{value}">{{value.firstname}} {{value.lastname}}</template>
|
||||
<template #defaultlabel><span class='text-primary'><?php t("showoverview"); ?></span></template>
|
||||
<template #defaultlabel><span class='text-primary'><?php t("coacheditmode"); ?></span></template>
|
||||
</s-prevnext-selector>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -103,15 +104,14 @@ print $OUTPUT->header();
|
|||
>{{selectedstudent.firstname}} {{selectedstudent.lastname}} - {{displayedstudyplan.name}}</h2>
|
||||
<h2 v-else-if='displayedstudyplan'><?php t("showoverview"); ?> - {{displayedstudyplan.name}}</h2>
|
||||
<template v-if="!loadingstudyplan && displayedstudyplan">
|
||||
<r-studyplan v-if="!editmode"
|
||||
v-model='displayedstudyplan' :teachermode='!selectedstudent'
|
||||
<r-studyplan v-if="selectedstudent"
|
||||
v-model='displayedstudyplan'
|
||||
coaching
|
||||
></r-studyplan>
|
||||
<t-studyplan
|
||||
v-else
|
||||
v-model='displayedstudyplan'
|
||||
@toggletoolbox="toggletoolbox"
|
||||
@pagechanged="onPageChange"
|
||||
coachmode
|
||||
coaching
|
||||
></t-studyplan>
|
||||
</template>
|
||||
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
|
||||
|
|
|
@ -284,6 +284,7 @@ $string["selectstudent_btn"] = "View student plans";
|
|||
$string["selectstudent"] = "Choose student";
|
||||
$string["selectstudent_details"] = "Pick a student from the list below to see their progress in this study plan";
|
||||
$string["showoverview"] = "Teacher view";
|
||||
$string["coacheditmode"] = "Edit content";
|
||||
$string["open"] = "Open";
|
||||
$string["noenddate"] = "Ongoing";
|
||||
$string["back"] = "Back";
|
||||
|
@ -468,6 +469,7 @@ $string["settingdesc_premium_key"] = 'Paste the premium key you received in the
|
|||
|
||||
$string["premiumfeature:morestudyplans"] = 'Creating more than 5 studyplans in a single category is a premium feature.';
|
||||
$string["premiumfeature:morecategories"] = 'Creating studyplans in more than 20 categories is a premium feature.';
|
||||
$string["premiumfeature:warning"] = 'The features on this page are only accessible if your site has premium features enabled.';
|
||||
$string["overall"] = 'Course';
|
||||
$string["studyplan_report"] = 'Studyplan result overview';
|
||||
$string["overviewreport:all"] = 'Result overview';
|
||||
|
@ -490,4 +492,4 @@ $string["line_cannot_enrol"] = 'You cannot register yourself for this line';
|
|||
$string["line_can_enrol"] = 'You can register for this line';
|
||||
$string["line_is_enrolled"] = 'You are registered for this line';
|
||||
$string["line_enrolled_in"] = 'Registered in {$a}';
|
||||
|
||||
$string["switch_coach_editmode"] = "Edit studyplan";
|
||||
|
|
|
@ -285,6 +285,7 @@ $string["selectstudent_btn"] = "Bekijk studentenvoortgang";
|
|||
$string["selectstudent"] = "Kies een student";
|
||||
$string["selectstudent_details"] = "Kies een student uit de lijst om zijn/haar voortgang in dit studieplan te bekijken";
|
||||
$string["showoverview"] = "Docentenweergave";
|
||||
$string["coacheditmode"] = "Bewerk inhoud";
|
||||
$string["open"] = "Openen";
|
||||
$string["noenddate"] = "∞";
|
||||
$string["back"] = "Terug";
|
||||
|
@ -469,6 +470,7 @@ $string["settingdesc_premium_key"] = 'Premium activation key';
|
|||
|
||||
$string["premiumfeature:morestudyplans"] = 'Meer dan 5 studieplannen in één categorie aanmaken kan alleen met premium toegang.';
|
||||
$string["premiumfeature:morecategories"] = 'In meer dan 20 categoriën een studieplan aanmaken kan alleen met premium toegang.';
|
||||
$string["premiumfeature:warning"] = 'De fucnties in deze pagina kun je alleen gebruiken met premium toegang.';
|
||||
$string["overall"] = 'Cursus voltooid';
|
||||
$string["studyplan_report"] = 'Studieplan resultatenoverzicht';
|
||||
$string["overviewreport:all"] = 'Resultatenoverzicht';
|
||||
|
@ -491,3 +493,4 @@ $string["line_cannot_enrol"] = 'Je kunt je niet zelf inschrijven voor deze leerl
|
|||
$string["line_can_enrol"] = 'Je kunt jezelf inschrijven voor deze leerlijn';
|
||||
$string["line_is_enrolled"] = 'Je bent ingeschreven voor deze leerlijn';
|
||||
$string["line_enrolled_in"] = 'Ingeschreven in {$a}';
|
||||
$string["switch_coach_editmode"] = "Studieplan bewerken";
|
84
lib.php
84
lib.php
|
@ -416,15 +416,12 @@ function local_treestudyplan_pluginfile(
|
|||
|
||||
|
||||
// Make sure the filearea is one of those used by the plugin.
|
||||
if (in_array($filearea,["studyplan","icon"])) {
|
||||
if (in_array($filearea,["studyplan","icon","studyplanpage"])) {
|
||||
// The args is an array containing [itemid, path].
|
||||
// Fetch the itemid from the path.
|
||||
$itemid = array_shift($args);
|
||||
|
||||
$plan = studyplan::find_by_id($itemid);
|
||||
$planctx = $plan->context();
|
||||
|
||||
// Studyplan icons are not secret, so don't check for access..
|
||||
// Studyplan icons and description images are not secret, so don't overdo it on access control...
|
||||
if ( true ) {
|
||||
// Extract the filename / filepath from the $args array
|
||||
$filename = array_pop($args); // The last item in the $args array.
|
||||
|
@ -449,40 +446,6 @@ function local_treestudyplan_pluginfile(
|
|||
return false;
|
||||
}
|
||||
|
||||
} else if (in_array($filearea,["studyplanpage"])) {
|
||||
// The args is an array containing [itemid, path].
|
||||
// Fetch the itemid from the path.
|
||||
$itemid = array_shift($args);
|
||||
|
||||
$page = studyplanpage::find_by_id($itemid);
|
||||
$plan = $page->studyplan();
|
||||
$planctx = $plan->context();
|
||||
|
||||
// Check if the current user has access to this studyplan
|
||||
if ( webservicehelper::has_capabilities($studyplan_filecaps,$planctx) || $plan->has_linked_user($USER)) {
|
||||
// Extract the filename / filepath from the $args array
|
||||
$filename = array_pop($args); // The last item in the $args array.
|
||||
if (empty($args)) {
|
||||
// $args is empty => the path is '/'.
|
||||
$filepath = '/';
|
||||
} else {
|
||||
// $args contains the remaining elements of the filepath.
|
||||
$filepath = '/' . implode('/', $args) . '/';
|
||||
}
|
||||
|
||||
// Retrieve the file from the Files API.
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file(\context_system::instance()->id, 'local_treestudyplan', $filearea, $itemid, $filepath, $filename);
|
||||
if (!$file) {
|
||||
// The file does not exist.
|
||||
return false;
|
||||
}
|
||||
// We can now send the file back to the browser - in this case with a cache lifetime of 1 day and no filtering.
|
||||
send_stored_file($file, 24*60*60, 0, $forcedownload, $options);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (in_array($filearea,['defaulticon'])) {
|
||||
// The args is an array containing [itemid, path].
|
||||
// Fetch the itemid from the path.
|
||||
|
@ -514,46 +477,3 @@ function local_treestudyplan_pluginfile(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Things to do on the start of every instance.
|
||||
*
|
||||
* Beware: do not access theme in this function, find another hook!!
|
||||
*/
|
||||
/*
|
||||
function local_treestudyplan_after_config() {
|
||||
global $PAGE;
|
||||
|
||||
/* WARNINGS from the documentation about this callback:
|
||||
This callback is very "raw" and so there are a number of edge cases that you should think about and possibly protect against. If this callback throws an exception that means you can very easily brick your moodle site
|
||||
|
||||
- running while in unit tests
|
||||
- during install
|
||||
- during upgrade
|
||||
- generic exceptions of any type
|
||||
|
||||
Also depending on the defines set before config.php is required, you may not have a $USER object, or other apis, eg if ABORT_AFTER_CONFIG or NO_MOODLE_COOKIES is defined. */
|
||||
/*
|
||||
// So, catch all exceptions to avoid page breaking. We should never break the page in this function.
|
||||
try {
|
||||
// Check if $PAGE is available and valid for use.
|
||||
if (!empty($PAGE) && is_object($PAGE) && method_exists($PAGE,"add_body_class")) {
|
||||
// Check to see if the theme is based on classic or boost to see if we need to add a polyfill...
|
||||
$bootstrapbased = false;
|
||||
foreach ($PAGE->theme->parents as $p) {
|
||||
if ($p->name == 'boost' || $p->name == 'classic') {
|
||||
$bootstrapbased = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bootstrapbased) {
|
||||
//$PAGE->add_body_class("bootstrap-polyfill"); // Enable the polyfill for boost styling.
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Exception $x) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue
Block a user