Reworked advanced tools

This commit is contained in:
PMKuipers 2023-11-11 20:17:45 +01:00
parent a60c259408
commit c3278f687c
12 changed files with 406 additions and 210 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -115,23 +115,33 @@ export default {
advanced_warning: 'advanced_warning', advanced_warning: 'advanced_warning',
advanced_pick_scale: 'advanced_pick_scale', advanced_pick_scale: 'advanced_pick_scale',
advanced_course_manipulation_title: 'advanced_course_manipulation_title', advanced_course_manipulation_title: 'advanced_course_manipulation_title',
advanced_bulk_course_timing: 'advanced_bulk_course_timing',
advanced_bulk_course_timing_desc: 'advanced_bulk_course_timing_desc',
advanced_force_scale_title: 'advanced_force_scale_title', advanced_force_scale_title: 'advanced_force_scale_title',
advanced_force_scale_desc: 'advanced_force_scale_desc', advanced_force_scale_desc: 'advanced_force_scale_desc',
advanced_force_scale_button: 'advanced_force_scale_button', advanced_force_scale_button: 'advanced_force_scale_button',
advanced_disable_autoenddate_title: 'advanced_disable_autoenddate_title',
advanced_disable_autoenddate_desc: 'advanced_disable_autoenddate_desc',
advanced_disable_autoenddate_button: 'advanced_disable_autoenddate_button',
advanced_confirm_header: 'advanced_confirm_header', advanced_confirm_header: 'advanced_confirm_header',
advanced_force_scale_confirm: 'advanced_force_scale_confirm', advanced_force_scale_confirm: 'advanced_force_scale_confirm',
advanced_import: 'advanced_import', advanced_backup_restore: 'advanced_backup_restore',
advanced_restore: 'advanced_restore',
advanced_backup: 'advanced_backup',
advanced_restore_pages: 'advanced_restore_pages',
advanced_restore_lines: 'advanced_restore_lines',
advanced_backup_plan: 'advanced_backup_plan',
advanced_backup_page: 'advanced_backup_page',
advanced_export: 'advanced_export', advanced_export: 'advanced_export',
advanced_export_csv: 'advanced_export_csv', advanced_export_csv_plan: 'advanced_export_csv_plan',
advanced_export_csv_page: 'advanced_export_csv_page',
advanced_import_from_file: 'advanced_import_from_file', advanced_import_from_file: 'advanced_import_from_file',
advanced_purge: "advanced_purge", advanced_purge: "advanced_purge",
advanced_purge_expl: "advanced_purge_expl", advanced_purge_plan: "advanced_purge_plan",
advanced_purge_plan_expl: "advanced_purge_plan_expl",
advanced_purge_page: "advanced_purge_page",
advanced_purge_page_expl: "advanced_purge_page_expl",
advanced_cascade_cohortsync_title: "advanced_cascade_cohortsync_title", advanced_cascade_cohortsync_title: "advanced_cascade_cohortsync_title",
advanced_cascade_cohortsync_desc: "advanced_cascade_cohortsync_desc", advanced_cascade_cohortsync_desc: "advanced_cascade_cohortsync_desc",
advanced_cascade_cohortsync: "advanced_cascade_cohortsync", advanced_cascade_cohortsync: "advanced_cascade_cohortsync",
currentpage: "currentpage",
}, },
studyplan_edit: { studyplan_edit: {
studyplan_edit: 'studyplan_edit', studyplan_edit: 'studyplan_edit',
@ -243,6 +253,10 @@ export default {
type: Object, type: Object,
default(){ return null;}, default(){ return null;},
}, },
selectedpage: {
type: Object,
default(){ return null;},
}
}, },
data() { data() {
@ -271,18 +285,6 @@ export default {
}, },
}, },
methods: { methods: {
disable_autoenddate(){
const self=this;
call([{
methodname: 'local_treestudyplan_disable_autoenddate',
args: {
studyplan_id: this.value.id,
}
}])[0].done(function(response){
self.$bvModal.msgBoxConfirm((response.success?self.text.success$core:self.text.error$core)
+ "\n" + response.msg);
}).fail(notification.exception);
},
force_scales_start(){ force_scales_start(){
// set confirmation box // set confirmation box
const self=this; const self=this;
@ -305,20 +307,49 @@ export default {
} }
}); });
}, },
export_plan(format){ export_page(format){
const self = this; const self = this;
if(format == undefined || !["json","csv"].includes(format)){ if(format == undefined || !["json","csv"].includes(format)){
format = "json"; format = "json";
} }
call([{ call([{
methodname: 'local_treestudyplan_export_plan', methodname: 'local_treestudyplan_export_page',
args: { args: {
studyplan_id: this.value.id, page_id: this.selectedpage.id,
format: format, format: format,
}, },
}])[0].done(function(response){ }])[0].done(function(response){
download(self.value.shortname+"."+format,response.content,response.format); download(self.value.shortname+".page."+format,response.content,response.format);
}).fail(notification.exception);
},
export_plan(){
const self = this;
call([{
methodname: 'local_treestudyplan_export_plan',
args: {
studyplan_id: this.value.id,
format: "json",
},
}])[0].done(function(response){
download(self.value.shortname+".plan.json",response.content,response.format);
}).fail(notification.exception);
},
bulk_course_timing() {
const self = this;
call([{
methodname: 'local_treestudyplan_bulk_course_timing',
args: {
page_id: this.selectedpage.id,
},
}])[0].done(function(response){
if(response.success){
// Reloading the webpage saves trouble reloading the specific page updated.
location.reload();
} else {
this.$bvModal.msgBoxOk(response.msg, {title: "Could not set bulk course timing"} );
debug.error("Could not set bulk course timing: ",response.msg);
}
}).fail(notification.exception); }).fail(notification.exception);
}, },
import_studylines(){ import_studylines(){
@ -326,6 +357,26 @@ export default {
upload((filename,content)=>{ upload((filename,content)=>{
call([{ call([{
methodname: 'local_treestudyplan_import_studylines', methodname: 'local_treestudyplan_import_studylines',
args: {
page_id: this.selectedpage.id,
content: content,
format: "application/json",
},
}])[0].done(function(response){
if(response.success){
location.reload();
} else {
this.$bvModal.msgBoxOk(response.msg, {title: "Import failed"} );
debug.error("Import failed: ",response.msg);
}
}).fail(notification.exception);
}, "application/json");
},
import_pages(){
//const self = this;
upload((filename,content)=>{
call([{
methodname: 'local_treestudyplan_import_pages',
args: { args: {
studyplan_id: this.value.id, studyplan_id: this.value.id,
content: content, content: content,
@ -335,13 +386,13 @@ export default {
if(response.success){ if(response.success){
location.reload(); location.reload();
} else { } else {
this.$bvModal.msgBoxOk(response.msg, {title: "Import failed"} );
debug.error("Import failed: ",response.msg); debug.error("Import failed: ",response.msg);
} }
}).fail(notification.exception); }).fail(notification.exception);
}, "application/json"); }, "application/json");
}, },
purge_studyline(){ purge_studyplan(){
call([{ call([{
methodname: 'local_treestudyplan_delete_studyplan', methodname: 'local_treestudyplan_delete_studyplan',
args: { args: {
@ -352,11 +403,29 @@ export default {
if(response.success){ if(response.success){
location.reload(); location.reload();
} else { } else {
this.$bvModal.msgBoxOk(response.msg, {title: "Could not delete plan "} );
debug.error("Could not delete plan: ",response.msg); debug.error("Could not delete plan: ",response.msg);
} }
}).fail(notification.exception); }).fail(notification.exception);
}, },
purge_studyplanpage(){
if (this.selectedpage) {
call([{
methodname: 'local_treestudyplan_delete_studyplanpage',
args: {
id: this.selectedpage.id,
force: true,
},
}])[0].done(function(response){
if(response.success){
location.reload();
} else {
this.$bvModal.msgBoxOk(response.msg, {title: "Could not delete page"} );
debug.error("Could not delete page: ",response.msg);
}
}).fail(notification.exception);
}
},
cascade_cohortsync(){ cascade_cohortsync(){
const self = this; const self = this;
call([{ call([{
@ -388,98 +457,99 @@ export default {
:title="text.advanced_tools_heading" :title="text.advanced_tools_heading"
ok-only ok-only
@hide="modal_close" @hide="modal_close"
body-class="p-0"
> >
<b-card no-body>
<b-tabs card> <b-tabs card>
<b-tab :title="text.advanced_warning_title" active> <b-tab :title="text.advanced_warning_title" active>
{{ text.advanced_warning}} {{ text.advanced_warning}}
</b-tab> </b-tab>
<b-tab :title="text.advanced_course_manipulation_title" > <b-tab :title="text.advanced_course_manipulation_title" >
<b-container> <h3>{{ text.advanced_cascade_cohortsync_title}}</h3>
<b-row><b-col cols="*"> <p>{{ text.advanced_cascade_cohortsync_desc}}</p>
<h3>{{ text.advanced_cascade_cohortsync_title}}</h3> <p class="mt-2"><b-button
{{ text.advanced_cascade_cohortsync_desc}}
</b-col></b-row>
<b-row><b-col cols="*">
<b-button
variant="info" variant="info"
@click="cascade_cohortsync" @click="cascade_cohortsync"
>{{ text.advanced_cascade_cohortsync}}</b-button> >{{ text.advanced_cascade_cohortsync}}</b-button></p>
</b-col></b-row> <h3>{{ text.advanced_bulk_course_timing}}</h3>
<b-row class="mt-3"><b-col cols="*"> <p>{{ text.advanced_bulk_course_timing_desc}}</p>
<h3>{{ text.advanced_force_scale_title}}</h3> <p>{{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>
<p class="mt-2"><b-button
variant="info"
@click="bulk_course_timing"
>{{ text.advanced_bulk_course_timing}}</b-button></p>
<template v-if="['bistate','tristate'].includes(value.aggregation)">
<h3>{{ text.advanced_force_scale_title}}</h3>
{{ text.advanced_force_scale_desc}} {{ text.advanced_force_scale_desc}}
</b-col></b-row> <p class="mt-2"><b-form-select v-model="force_scales.selected_scale"
<b-row>
<b-col>
<b-form-select v-model="force_scales.selected_scale"
:options="scales" text-field="name" value-field="id" :options="scales" text-field="name" value-field="id"
></b-form-select> ></b-form-select>
</b-col> <b-button
<b-col cols="4"> variant="danger"
<b-button :disabled="force_scales.selected_scale == null"
variant="danger" @click="force_scales_start"
:disabled="force_scales.selected_scale == null" >{{ text.advanced_force_scale_button}}</b-button>
@click="force_scales_start" </p>
>{{ text.advanced_force_scale_button}}</b-button> <p class="mt-2">
</b-col>
</b-row>
<b-row class="mt-3"><b-col cols="*">
<ul class='t-advanced-scrollable' v-if="force_scales.result.length > 0"> <ul class='t-advanced-scrollable' v-if="force_scales.result.length > 0">
<li v-for="c in force_scales.result"> <li v-for="c in force_scales.result">
<span class='t-advanced-coursename'>{{c.course.fullname}}</span> <span class='t-advanced-coursename'>{{c.course.fullname}}</span>
<ul v-if="c.grades.length > 0"> <ul v-if="c.grades.length > 0">
<li v-for='g in c.grades'> <li v-for='g in c.grades'
<span class='t-advanced-gradename'><span v-html="g.name"></span></span> ><span class='t-advanced-gradename'><span v-html="g.name"></span></span>
<span v-if="g.changed == 'converted'" class='t-advanced-status changed' <span v-if="g.changed == 'converted'" class='t-advanced-status changed'
>{{text.advanced_converted}}</span >{{text.advanced_converted}}</span
><span v-else-if="g.changed == 'skipped'" class='t-advanced-status skipped' ><span v-else-if="g.changed == 'skipped'" class='t-advanced-status skipped'
>{{text.advanced_skipped}}</span >{{text.advanced_skipped}}</span
> ><span v-else class='t-advanced-status skipped'
<span v-else class='t-advanced-status skipped'
>{{text.advanced_error}}</span >{{text.advanced_error}}</span
> ></li>
</li>
</ul> </ul>
</li> </li>
</ul> </ul>
</b-col></b-row> </p>
<b-row><b-col cols="*"> </template>
<h3>{{ text.advanced_disable_autoenddate_title}}</h3>
{{ text.advanced_disable_autoenddate_desc}}
</b-col></b-row>
<b-row><b-col cols="*">
<b-button
variant="danger"
@click="disable_autoenddate"
>{{ text.advanced_disable_autoenddate_button}}</b-button>
</b-col></b-row>
</b-container>
</b-tab> </b-tab>
<b-tab :title='text.advanced_export'> <b-tab :title='text.advanced_backup_restore'>
<b-button <h3>{{ text.advanced_backup }}</h3>
variant="primary" <p><b-button
@click="export_plan"
>{{ text.advanced_export}}</b-button>
<b-button
variant="danger"
@click="import_studylines"
>{{ text.advanced_import}}</b-button>
<b-button
variant="primary" variant="primary"
@click="export_plan('csv')" @click="export_page('json')"
>{{ text.advanced_export_csv}}</b-button> >{{ text.advanced_backup_page }}</b-button>
{{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>
<p><b-button
variant="primary"
@click="export_plan('json')"
>{{ text.advanced_backup_plan }}</b-button></p>
<h3>{{ text.advanced_restore }}</h3>
<p><b-button
variant="danger"
@click="import_studylines"
>{{ text.advanced_restore_lines}}</b-button></p>
<p><b-button
variant="danger"
@click="import_pages"
>{{ text.advanced_restore_pages }}</b-button></p>
<h3>{{ text.advanced_export }}</h3>
<p><b-button
variant="primary"
@click="export_page('csv')"
>{{ text.advanced_export_csv_page }}</b-button>
{{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>
</b-tab> </b-tab>
<b-tab :title='text.advanced_purge'> <b-tab :title='text.advanced_purge'>
<p>{{text.advanced_purge_expl}}</p> <p>{{text.advanced_purge_page_expl}}</p>
<p>{{text.currentpage}} <i>{{selectedpage.fullname}}</i></p>
<p><b-button <p><b-button
variant="danger" variant="danger"
@click="purge_studyline" @click="purge_studyplanpage"
>{{ text.advanced_purge}}</b-button></p> >{{ text.advanced_purge_page}}</b-button></p>
<p>{{text.advanced_purge_plan_expl}}</p>
<p><b-button
variant="danger"
@click="purge_studyplan"
>{{ text.advanced_purge_plan}}</b-button></p>
</b-tab> </b-tab>
</b-tabs> </b-tabs>
</b-card>
</b-modal> </b-modal>
</span> </span>
` `
@ -1182,7 +1252,7 @@ export default {
}, },
mounted() { mounted() {
if(this.value.pages[0].studylines.length == 0){ if(this.value.pages[0].studylines.length == 0){
// start in editmode if studylines are empty // start in editmode if studylines on first page are empty
this.edit.studyline.editmode = true; this.edit.studyline.editmode = true;
} }
this.$root.$emit('redrawLines'); this.$root.$emit('redrawLines');
@ -1472,7 +1542,7 @@ export default {
</div> </div>
<div class="controlbox-group"> <div class="controlbox-group">
<span class='control editable'> <span class='control editable'>
<t-studyplan-advanced v-model="value"></t-studyplan-advanced> <t-studyplan-advanced v-model="value" :selectedpage="selectedpage"></t-studyplan-advanced>
</span> </span>
<span class='control editable'> <span class='control editable'>
<t-studyplan-associate <t-studyplan-associate
@ -2635,12 +2705,7 @@ export default {
// Listener for reposition events // Listener for reposition events
// When an item in the list is repositioned, all lines need to be redrawn // When an item in the list is repositioned, all lines need to be redrawn
onRePositioned(){ onRePositioned(){
if(this.value.connections && this.value.connections.out){ this.redrawLines();
for(let i in this.value.connections.out){
let conn = this.value.connections.out[i];
this.redrawLine(conn);
}
}
}, },
// When an item is disPositioned - (temporarily) removed from the list, // When an item is disPositioned - (temporarily) removed from the list,
// all connections need to be deleted. // all connections need to be deleted.

View file

@ -139,6 +139,13 @@ class studyitem {
return $this->r->type; return $this->r->type;
} }
/**
* Return period span
*/
public function span() : string {
return $this->r->span;
}
/** /**
* Return id of linked course (only relevant on COURSE types) or 0 if none * Return id of linked course (only relevant on COURSE types) or 0 if none
*/ */

View file

@ -699,7 +699,7 @@ class studyplan {
public static function export_structure() : \external_description { public static function export_structure() : \external_description {
return new \external_single_structure([ return new \external_single_structure([
"format" => new \external_value(PARAM_TEXT, 'format of studyplan export'), "format" => new \external_value(PARAM_TEXT, 'format of studyplan export'),
"content" => new \external_value(PARAM_TEXT, 'exported studyplan content'), "content" => new \external_value(PARAM_RAW, 'exported studyplan content'),
], 'Exported studyplan'); ], 'Exported studyplan');
} }

View file

@ -479,7 +479,7 @@ class studyplanpage {
public static function export_structure() : \external_description { public static function export_structure() : \external_description {
return new \external_single_structure([ return new \external_single_structure([
"format" => new \external_value(PARAM_TEXT, 'format of studyplan export'), "format" => new \external_value(PARAM_TEXT, 'format of studyplan export'),
"content" => new \external_value(PARAM_TEXT, 'exported studyplan content'), "content" => new \external_value(PARAM_RAW, 'exported studyplan content'),
], 'Exported studyplan'); ], 'Exported studyplan');
} }

View file

@ -1097,60 +1097,6 @@ class studyplanservice extends \external_api {
} }
/****************************
* *
* disable_autoenddate *
* *
****************************/
/**
* Parameter description for webservice function disable_autoenddate
*/
public static function disable_autoenddate_parameters() : \external_function_parameters {
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan'),
] );
}
/**
* Return value description for webservice function disable_autoenddate
*/
public static function disable_autoenddate_returns() : \external_description {
return success::structure();
}
/**
* Disable automatic end date for all courses in a study plan
* @param int $studyplanid Id of the studyplan
* @return array Success/fail model
*/
public static function disable_autoenddate($studyplanid) {
global $DB;
// Validate permissions.
webservicehelper::require_capabilities(self::CAP_EDIT, studyplan::find_by_id($studyplanid)->context());
// Find studyline id's.
$studylineids = $DB->get_fieldset_select(studyline::TABLE, "id", "studyplan_id = :plan_id", ['plan_id' => $studyplanid]);
foreach ($studylineids as $studylineid) {
// Find id's of studyitems of type course.
$records = $DB->get_records(studyitem::TABLE, ['line_id' => $studylineid]);
foreach ($records as $itemr) {
$studyitem = new studyitem($itemr->id);
if ($studyitem->valid() && $studyitem->type() == studyitem::COURSE) {
$record = $DB->get_record("course_format_options",
["courseid" => $studyitem->courseid(), "name" => "automaticenddate"]);
if ($record && $record->value) {
$record->value = false;
$DB->update_record("course_format_options", $record);
}
}
}
}
return success::success()->model();
}
/**************************** /****************************
* * * *
* duplicate studyplan * * duplicate studyplan *
@ -1225,12 +1171,7 @@ class studyplanservice extends \external_api {
webservicehelper::require_capabilities(self::CAP_EDIT, studyplan::find_by_id($studyplanid)->context()); webservicehelper::require_capabilities(self::CAP_EDIT, studyplan::find_by_id($studyplanid)->context());
$plan = studyplan::find_by_id($studyplanid); $plan = studyplan::find_by_id($studyplanid);
if ($format == "csv") { return $plan->export_plan();
// FIXME: Make sure this webservice function gets called for the page instead of the studyplan.
return $plan->pages()[0]->export_page_csv();
} else {
return $plan->export_plan();
}
} catch (\webservice_access_exception $x) { } catch (\webservice_access_exception $x) {
return [ "format" => "", "content" => ""]; return [ "format" => "", "content" => ""];
} }
@ -1239,34 +1180,41 @@ class studyplanservice extends \external_api {
/** /**
* Parameter description for webservice function export_studylines * Parameter description for webservice function export_studylines
*/ */
public static function export_studylines_parameters() : \external_function_parameters { public static function export_page_parameters() : \external_function_parameters {
return new \external_function_parameters( [ return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of plan to export '), "page_id" => new \external_value(PARAM_INT, 'id of plan to export '),
"format" => new \external_value(PARAM_TEXT, 'export format', VALUE_OPTIONAL),
] ); ] );
} }
/** /**
* Return value description for webservice function export_studylines * Return value description for webservice function export_studylines
*/ */
public static function export_studylines_returns() : \external_description { public static function export_page_returns() : \external_description {
return studyplan::export_structure(); return studyplanpage::export_structure();
} }
/** /**
* Export studylines for a studyplan * Export studylines for a studyplan
* @param mixed $studyplanid Id of the studyplan to export the studylines for * @param mixed $studyplanid Id of the studyplan to export the studylines for
* @param string $format Export format [csv, json (default)]
* @return array * @return array
*/ */
public static function export_studylines($studyplanid) { public static function export_page($pageid,$format="json") {
try { try {
webservicehelper::require_capabilities(self::CAP_EDIT, studyplan::find_by_id($studyplanid)->context()); $page = studyplanpage::find_by_id($pageid);
$plan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $page->studyplan()->context());
// FIXME: Make sure this gets called for the page instead of the studyplan. if ($format == "csv") {
return $plan->pages()[0]->export_studylines(); return $page->export_page_csv();
} else {
return $page->export_page();
}
} catch (\webservice_access_exception $x) { } catch (\webservice_access_exception $x) {
return [ "format" => "", "content" => ""]; return [ "format" => "", "content" => ""];
} }
} }
/**************************** /****************************
* * * *
* import studyplan * * import studyplan *
@ -1278,7 +1226,7 @@ class studyplanservice extends \external_api {
*/ */
public static function import_plan_parameters() : \external_function_parameters { public static function import_plan_parameters() : \external_function_parameters {
return new \external_function_parameters( [ return new \external_function_parameters( [
"content" => new \external_value(PARAM_TEXT, 'import file content'), "content" => new \external_value(PARAM_RAW, 'import file content'),
"format" => new \external_value(PARAM_TEXT, 'import format'), "format" => new \external_value(PARAM_TEXT, 'import format'),
"context_id" => new \external_value(PARAM_INT, 'context of the study plan', VALUE_DEFAULT), "context_id" => new \external_value(PARAM_INT, 'context of the study plan', VALUE_DEFAULT),
] ); ] );
@ -1312,13 +1260,50 @@ class studyplanservice extends \external_api {
} }
} }
/**
* Parameter description for webservice function import_studylines
*/
public static function import_pages_parameters() : \external_function_parameters {
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan to import to '),
"content" => new \external_value(PARAM_RAW, 'import file content'),
"format" => new \external_value(PARAM_TEXT, 'import format'),
] );
}
/**
* Return value description for webservice function import_studylines
*/
public static function import_pages_returns() : \external_description {
return success::structure();
}
/**
* Import studylines into existing studtplan
* @param int $studyplanid ID of studyplan to import to
* @param string $content Content of file
* @param string $format Format of file
* @return array Success/fail model
*/
public static function import_pages($studyplanid, $content, $format = "application/json") {
try {
$plan = studyplan::find_by_id($studyplanid);
// Validate import context.
webservicehelper::require_capabilities(self::CAP_EDIT, $plan->context());
$result = $plan->import_pages($content, $format);
return ($result ? success::success() : success::fail())->model();
} catch (\webservice_access_exception $x) {
return success::fail("Access denied")->model();
}
}
/** /**
* Parameter description for webservice function import_studylines * Parameter description for webservice function import_studylines
*/ */
public static function import_studylines_parameters() : \external_function_parameters { public static function import_studylines_parameters() : \external_function_parameters {
return new \external_function_parameters( [ return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of plan to export '), "page_id" => new \external_value(PARAM_INT, 'id of studyplan page to import to '),
"content" => new \external_value(PARAM_TEXT, 'import file content'), "content" => new \external_value(PARAM_RAW, 'import file content'),
"format" => new \external_value(PARAM_TEXT, 'import format'), "format" => new \external_value(PARAM_TEXT, 'import format'),
] ); ] );
} }
@ -1337,15 +1322,13 @@ class studyplanservice extends \external_api {
* @param string $format Format of file * @param string $format Format of file
* @return array Success/fail model * @return array Success/fail model
*/ */
public static function import_studylines($studyplanid, $content, $format = "application/json") { public static function import_studylines($page_id, $content, $format = "application/json") {
try { try {
$plan = studyplan::find_by_id($studyplanid); $page = studyplanpage::find_by_id($page_id);
// Validate import context. // Validate import context.
webservicehelper::require_capabilities(self::CAP_EDIT, $plan->context()); webservicehelper::require_capabilities(self::CAP_EDIT, $page->studyplan()->context());
// FIXME: Make sure this gets called for the page instead of the studyplan. $result = $page->import_studylines($content, $format);
// Once proper page management is implemented.
$result = $plan->pages()[0]->import_studylines($content, $format);
return ($result ? success::success() : success::fail())->model(); return ($result ? success::success() : success::fail())->model();
} catch (\webservice_access_exception $x) { } catch (\webservice_access_exception $x) {
return success::fail("Access denied")->model(); return success::fail("Access denied")->model();
@ -1636,4 +1619,107 @@ class studyplanservice extends \external_api {
} }
/************************
* *
* bulk_course_timing *
* *
************************/
/**
* Parameter description for webservice function delete_studyplan
*/
public static function bulk_course_timing_parameters() : \external_function_parameters {
return new \external_function_parameters( [
"page_id" => new \external_value(PARAM_INT, 'id of studyplanpage'),
] );
}
/**
* Return value description for webservice function delete_studyplan
*/
public static function bulk_course_timing_returns() : \external_description {
return success::structure();
}
/**
* Delete a studyplan
* @param mixed $id Id of the studyplan
* @param bool $force Force deletion, even though studyplan is not empty
* @return array Succes/fail model
*/
public static function bulk_course_timing($pageid) {
$page = studyplanpage::find_by_id($pageid);
// Validate if the requesting user has the right to edit the plan in it's current context.
webservicehelper::require_capabilities(self::CAP_EDIT, $page->studyplan()->context());
$result = true;
$message = [];
$periods = period::find_for_page($page);
$studylines = studyline::find_page_children($page);
foreach ($studylines as $line) {
$studyitems = studyitem::find_studyline_children($line);
foreach ($studyitems as $item) {
if ($item->type() == studyitem::COURSE) {
if ( $item->slot() <= $page->periods() ) {
$period = $periods[$item->slot()];
try {
self::course_period_timing($period->id(),$item->courseid(),$item->span());
} catch (\webservice_access_exception $x) {
$result &= false;
$course = \get_course($item->courseid());
$message[] = "Course {$course->shortname}: {$x->debuginfo}";
} catch (\Exception $x) {
$result &= false;
$course = \get_course($item->courseid());
$xclass = \get_class($x);
$message[] = "Course {$course->shortname}: {$xclass} {$x->getMessage()}";
}
}
}
}
}
return (new success($result,implode("<p>\n",$message)))->model();
}
/************************
* *
* delete_studyplanpage *
* *
************************/
/**
* Parameter description for webservice function delete_studyplan
*/
public static function delete_studyplanpage_parameters() : \external_function_parameters {
return new \external_function_parameters( [
"id" => new \external_value(PARAM_INT, 'id of studyplanpage'),
"force" => new \external_value(PARAM_BOOL, 'force deletion', VALUE_DEFAULT),
] );
}
/**
* Return value description for webservice function delete_studyplan
*/
public static function delete_studyplanpage_returns() : \external_description {
return success::structure();
}
/**
* Delete a studyplan
* @param mixed $id Id of the studyplan
* @param bool $force Force deletion, even though studyplan is not empty
* @return array Succes/fail model
*/
public static function delete_studyplanpage($id, $force = false) {
$o = studyplanpage::find_by_id($id);
$p = $o->studyplan();
// Validate if the requesting user has the right to edit the plan in it's current context.
webservicehelper::require_capabilities(self::CAP_EDIT, $p->context());
return $o->delete(!!$force)->model();
}
} }

View file

@ -74,7 +74,7 @@ class success {
public static function structure() : \external_description { public static function structure() : \external_description {
return new \external_single_structure([ return new \external_single_structure([
"success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'),
"msg" => new \external_value(PARAM_TEXT, 'message'), "msg" => new \external_value(PARAM_RAW, 'message'),
"data" => new \external_value(PARAM_RAW, 'message'), "data" => new \external_value(PARAM_RAW, 'message'),
]); ]);
} }

View file

@ -137,6 +137,16 @@ $functions = [
'loginrequired' => true, 'loginrequired' => true,
], ],
'local_treestudyplan_delete_studyplanpage' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'delete_studyplanpage', // External function name.
'description' => 'Delete studyplan page',
'type' => 'write', // Database rights of the web service function (read, write).
'ajax' => true,
'capabilities' => 'local/treestudyplan:editstudyplan',
'loginrequired' => true,
],
'local_treestudyplan_delete_studyline' => [ // Web service function name. 'local_treestudyplan_delete_studyline' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function. 'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'delete_studyline', // External function name. 'methodname' => 'delete_studyline', // External function name.
@ -412,15 +422,6 @@ $functions = [
'capabilities' => 'local/treestudyplan:editstudyplan', 'capabilities' => 'local/treestudyplan:editstudyplan',
'loginrequired' => true, 'loginrequired' => true,
], ],
'local_treestudyplan_disable_autoenddate' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'disable_autoenddate', // External function name.
'description' => 'Disable automatic end dates on courses in the study plan',
'type' => 'write', // Database rights of the web service function (read, write).
'ajax' => true,
'capabilities' => 'local/treestudyplan:forcescales',
'loginrequired' => true,
],
'local_treestudyplan_force_studyplan_scale' => [ // Web service function name. 'local_treestudyplan_force_studyplan_scale' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function. 'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'force_studyplan_scale', // External function name. 'methodname' => 'force_studyplan_scale', // External function name.
@ -451,16 +452,16 @@ $functions = [
'local_treestudyplan_export_plan' => [ // Web service function name. 'local_treestudyplan_export_plan' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function. 'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'export_plan', // External function name. 'methodname' => 'export_plan', // External function name.
'description' => 'Export study plan', 'description' => 'Export studyplan',
'type' => 'read', // Database rights of the web service function (read, write). 'type' => 'read', // Database rights of the web service function (read, write).
'ajax' => true, 'ajax' => true,
'capabilities' => 'local/treestudyplan:editstudyplan', 'capabilities' => 'local/treestudyplan:editstudyplan',
'loginrequired' => true, 'loginrequired' => true,
], ],
'local_treestudyplan_export_studylines' => [ // Web service function name. 'local_treestudyplan_export_page' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function. 'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'export_studylines', // External function name. 'methodname' => 'export_page', // External function name.
'description' => 'Export study plan', 'description' => 'Export studyplan page',
'type' => 'read', // Database rights of the web service function (read, write). 'type' => 'read', // Database rights of the web service function (read, write).
'ajax' => true, 'ajax' => true,
'capabilities' => 'local/treestudyplan:editstudyplan', 'capabilities' => 'local/treestudyplan:editstudyplan',
@ -475,6 +476,15 @@ $functions = [
'capabilities' => 'local/treestudyplan:editstudyplan', 'capabilities' => 'local/treestudyplan:editstudyplan',
'loginrequired' => true, 'loginrequired' => true,
], ],
'local_treestudyplan_import_pages' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'import_pages', // External function name.
'description' => 'Import study plan pages',
'type' => 'write', // Database rights of the web service function (read, write).
'ajax' => true,
'capabilities' => 'local/treestudyplan:editstudyplan',
'loginrequired' => true,
],
'local_treestudyplan_import_studylines' => [ // Web service function name. 'local_treestudyplan_import_studylines' => [ // Web service function name.
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function. 'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
'methodname' => 'import_studylines', // External function name. 'methodname' => 'import_studylines', // External function name.
@ -609,4 +619,13 @@ $functions = [
'ajax' => true, 'ajax' => true,
'loginrequired' => true, 'loginrequired' => true,
], ],
'local_treestudyplan_bulk_course_timing' => [ // Web service function name.
'classname' => '\local_treestudyplan\utilityservice', // Class containing the external function.
'methodname' => 'bulk_course_timing', // External function name.
'description' => 'Change course start/end dates to match that of the studyplan period',
'type' => 'write', // Database rights of the web service function (read, write).
'capabilities' => 'local/treestudyplan:editstudyplan',
'ajax' => true,
'loginrequired' => true,
],
]; ];

View file

@ -303,23 +303,33 @@ $string["advanced_force_scale_button"] = 'Apply';
$string["advanced_confirm_header"] = 'Are you sure'; $string["advanced_confirm_header"] = 'Are you sure';
$string["advanced_force_scale_confirm"] = 'Are you sure you want to set all associated gradables to this scale?'; $string["advanced_force_scale_confirm"] = 'Are you sure you want to set all associated gradables to this scale?';
$string["advanced_import_export"] = 'Backup and restore'; $string["advanced_backup_restore"] = 'Backup and restore';
$string["advanced_import"] = 'Restore studylines from backup'; $string["advanced_restore"] = 'Restore from file';
$string["advanced_export"] = 'Backup study plan'; $string["advanced_backup"] = 'Backup to file';
$string["advanced_export_csv"] = 'Export as CSV'; $string["advanced_restore_pages"] = 'Import pages from a studyplan backup';
$string["advanced_import_from_file"] = "Open from file"; $string["advanced_restore_lines"] = 'Import content from a studyplan page backup';
$string["advanced_backup_plan"] = 'Backup studyplan';
$string["advanced_backup_page"] = 'Backup active studyplan page ';
$string["advanced_export"] = 'Export to file';
$string["advanced_export_csv_page"] = 'Export current page as CSV';
$string["advanced_export_csv_plan"] = 'Export studyplan CSV';
$string["advanced_import_from_file"] = "Restore studyplan from file";
$string["advanced_purge"] = "Delete"; $string["advanced_purge"] = "Delete";
$string["advanced_purge_expl"] = "Delete the entire study plan. This is not recoverable"; $string["advanced_purge_plan"] = "Delete entire study plan";
$string["advanced_purge_plan_expl"] = "Delete the entire study plan. This is not recoverable";
$string["advanced_purge_page"] = "Delete active page";
$string["advanced_purge_page_expl"] = "Delete the currently active study plan page. This is not recoverable";
$string["currentpage"] = "Currently active page:";
$string["advanced_bulk_course_timing"] = 'Sync course timing to periods';
$string["advanced_bulk_course_timing_desc"] = 'Synchronize the start and end date of all courses in the currently active studyplan page to periods in which they are placed.';
$string["advanced_cascade_cohortsync_title"] = "Cascade cohort sync"; $string["advanced_cascade_cohortsync_title"] = "Cascade cohort sync";
$string["advanced_cascade_cohortsync_desc"] = "Add cohort sync enrolment to each course in this study plan for all cohorts linked to this study plan"; $string["advanced_cascade_cohortsync_desc"] = "Add cohort sync enrolment to each course in this study plan for all cohorts linked to this study plan";
$string["advanced_cascade_cohortsync"] = "Cascade cohort sync"; $string["advanced_cascade_cohortsync"] = "Cascade cohort sync";
$string["advanced_course_manipulation_title"] = 'Course manipulation'; $string["advanced_course_manipulation_title"] = 'Course manipulation';
$string["advanced_disable_autoenddate_title"] = 'Disable automatic end date';
$string["advanced_disable_autoenddate_desc"] = 'Disable the default on automatic end date function weekly topics have set in all courses in the study plan';
$string["advanced_disable_autoenddate_button"] = 'Disable';
$string["myreport_teachermode"] = 'Study plans I am teaching'; $string["myreport_teachermode"] = 'Study plans I am teaching';
$string["aggregation_overall_all"] = "Complete all of the following to complete this course"; $string["aggregation_overall_all"] = "Complete all of the following to complete this course";

View file

@ -301,23 +301,32 @@ $string["advanced_force_scale_button"] = 'Toepassen';
$string["advanced_confirm_header"] = 'Weet je het zeker?'; $string["advanced_confirm_header"] = 'Weet je het zeker?';
$string["advanced_force_scale_confirm"] = 'Weet je zeker dat je de beoordeling van alle gekoppelde activiteiten wilt omzetten?'; $string["advanced_force_scale_confirm"] = 'Weet je zeker dat je de beoordeling van alle gekoppelde activiteiten wilt omzetten?';
$string["advanced_import_export"] = 'Backup and terugzetten'; $string["advanced_backup_restore"] = 'Backup and import';
$string["advanced_import"] = 'Studieplan invullan vanuit backup'; $string["advanced_restore"] = 'Laden vanuit bestand';
$string["advanced_export"] = 'Backup downloaden'; $string["advanced_backup"] = 'Backup naar bestand';
$string["advanced_export_csv"] = 'Export als CSV'; $string["advanced_restore_pages"] = 'Importeer tabbladen uit de backup van een studieplan';
$string["advanced_restore_lines"] = 'Importeer inhoud uit de backup van een tabblad';
$string["advanced_backup_plan"] = 'Backup studieplan';
$string["advanced_backup_page"] = 'Backup actieve tabblad ';
$string["advanced_export"] = 'Exporteer naar bestand';
$string["advanced_export_csv_page"] = 'Exporteer actieve tabblad naar CSV';
$string["advanced_export_csv_plan"] = 'Exporteer studeeplan naar CSV';
$string["advanced_import_from_file"] = "Vanuit bestand"; $string["advanced_import_from_file"] = "Vanuit bestand";
$string["advanced_purge"] = "Verwijderen"; $string["advanced_purge"] = "Verwijderen";
$string["advanced_purge_expl"] = "Dit hele studieplan permanent verwijderen."; $string["advanced_purge_plan"] = "Studieplan verwijderen";
$string["advanced_purge_plan_expl"] = "Dit hele studieplan permanent verwijderen.";
$string["advanced_purge_page"] = "Tabblad verwijderen";
$string["advanced_purge_page_expl"] = "Het actieve tabblad permanent verwijderen.";
$string["currentpage"] = "Actief tabblad:";
$string["advanced_bulk_course_timing"] = 'Stel start- en einddatum in';
$string["advanced_bulk_course_timing_desc"] = 'Stel de start- en einddatum van alle cursussen in het actieve tabblas in op die van de perioden waarin ze geplaatst zijn';
$string["advanced_cascade_cohortsync_title"] = "Site-groep synchronisatie doorzetten"; $string["advanced_cascade_cohortsync_title"] = "Site-groep synchronisatie doorzetten";
$string["advanced_cascade_cohortsync_desc"] = "Voeg een site-group synchronisatie aanmelding toe aan alle cursussen in dit studieplan, voor alle gekoppelde site-groepen"; $string["advanced_cascade_cohortsync_desc"] = "Voeg een site-group synchronisatie aanmelding toe aan alle cursussen in dit studieplan, voor alle gekoppelde site-groepen";
$string["advanced_cascade_cohortsync"] = "Site-groep sync doorzetten"; $string["advanced_cascade_cohortsync"] = "Site-groep sync doorzetten";
$string["advanced_course_manipulation_title"] = 'Cursussen aanpassen'; $string["advanced_course_manipulation_title"] = 'Cursussen aanpassen';
$string["advanced_disable_autoenddate_title"] = 'Automatische einddatum uitschakelen';
$string["advanced_disable_autoenddate_desc"] = 'Schakel de optie automatische einddatum uit in alle cursussen in dit studieplan';
$string["advanced_disable_autoenddate_button"] = 'Uitschakelen';
$string["myreport_teachermode"] = 'Studieplannen waar ik les aan geef'; $string["myreport_teachermode"] = 'Studieplannen waar ik les aan geef';
$string["aggregation_overall_all"] = "Je voltooit de module door alles van het volgende"; $string["aggregation_overall_all"] = "Je voltooit de module door alles van het volgende";

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 = 2023102401; // YYYYMMDDHH (year, month, day, iteration). $plugin->version = 2023111001; // 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.1.0-b"; $plugin->release = "1.1.0-b";