--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Model upload form.
+ *
+ * @package tool_analytics
+ * @copyright 2017 onwards Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics;
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Model upload form.
+ *
+ * @package tool_analytics
+ * @copyright 2017 onwards Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class import_model_form extends \moodleform {
+ function definition () {
+ $mform = $this->_form;
+
+ $mform->addElement('header', 'settingsheader', get_string('analyticsimportmodel', 'tool_analytics'));
+
+ $mform->addElement('filepicker', 'modelfile', get_string('file'), null, ['accepted_types' => '.json']);
+ $mform->addRule('modelfile', null, 'required');
+
+ $this->add_action_buttons(false, get_string('submit'));
+ }
+}
\ No newline at end of file
// Export training data.
if (!$model->is_static() && $model->is_trained()) {
- $urlparams['action'] = 'export';
+ $urlparams['action'] = 'exportdata';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('i/export',
get_string('exporttrainingdata', 'tool_analytics')), get_string('export', 'tool_analytics'));
$actionsmenu->add($icon);
}
+ // Export model.
+ if (!$model->is_static() && $model->get_indicators() && !empty($modeldata->timesplitting)) {
+ $urlparams['action'] = 'exportmodel';
+ $url = new \moodle_url('model.php', $urlparams);
+ $icon = new \action_menu_link_secondary($url, new \pix_icon('i/export',
+ get_string('exportmodel', 'tool_analytics')), get_string('exportmodel', 'tool_analytics'));
+ $actionsmenu->add($icon);
+ }
+
// Invalid analysables.
$analyser = $model->get_analyser(['notimesplitting' => true]);
if (!$analyser instanceof \core_analytics\local\analyser\sitewide) {
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Import models tool frontend.
+ *
+ * @package tool_analytics
+ * @copyright 2017 onwards Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir . '/adminlib.php');
+
+admin_externalpage_setup('analyticsmodelimport', '', null, '', array('pagelayout' => 'report'));
+echo $OUTPUT->header();
+
+$form = new tool_analytics\import_model_form();
+if ($data = $form->get_data()) {
+ $content = json_decode($form->get_file_content('modelfile'));
+ if (empty($content->moodleversion)) {
+ // Should never happen.
+ echo $OUTPUT->notification(get_string('missingmoodleversion', 'tool_analytics'), 'error');
+ } else {
+ if ($content->moodleversion != $CFG->version) {
+ $a = new stdClass();
+ $a->importedversion = $content->moodleversion;
+ $a->version = $CFG->version;
+ echo $OUTPUT->notification(get_string('versionnotsame', 'tool_analytics', $a), 'warning');
+ }
+ $model = \core_analytics\model::create_from_json($content);
+ if ($model) {
+ echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
+ } else {
+ echo $OUTPUT->notification(get_string('error'), 'error');
+ }
+ }
+ echo $OUTPUT->single_button(new moodle_url("$CFG->wwwroot/$CFG->admin/tool/analytics/index.php"),
+ get_string('continue'), 'get');
+} else {
+ $form->display();
+}
+
+echo $OUTPUT->footer();
\ No newline at end of file
$string['allpredictions'] = 'All predictions';
$string['analysingsitedata'] = 'Analysing the site';
$string['analyticmodels'] = 'Analytics models';
+$string['analyticsimportmodel'] = 'Import analytics model';
$string['bettercli'] = 'Evaluating models and generating predictions may involve heavy processing. It is recommended to run these actions from the command line.';
$string['cantguessstartdate'] = 'Can\'t guess the start date';
$string['cantguessenddate'] = 'Can\'t guess the end date';
+$string['classdoesnotexist'] = 'Class {$a} does not exist';
$string['clearpredictions'] = 'Clear predictions';
$string['clearmodelpredictions'] = 'Are you sure you want to clear all "{$a}" predictions?';
$string['clienablemodel'] = 'You can enable the model by selecting a time-splitting method by its ID. Note that you can also enable it later using the web interface (\'none\' to exit).';
$string['errornoenabledandtrainedmodels'] = 'There are no enabled and trained models to predict.';
$string['errornoenabledmodels'] = 'There are no enabled models to train.';
$string['errornoexport'] = 'Only trained models can be exported';
+$string['errornoexportconfg'] = 'Only non static models with timeplitting methods can be exported.';
$string['errornostaticedit'] = 'Models based on assumptions cannot be edited.';
$string['errornostaticevaluated'] = 'Models based on assumptions cannot be evaluated. They are always 100% correct according to how they were defined.';
$string['errornostaticlog'] = 'Models based on assumptions cannot be evaluated because there is no performance log.';
$string['evaluatemodel'] = 'Evaluate model';
$string['evaluationinbatches'] = 'The site contents are calculated and stored in batches. The evaluation process may be stopped at any time. The next time it is run, it will continue from the point when it was stopped.';
$string['export'] = 'Export';
+$string['exportmodel'] = 'Export model configuration';
$string['exporttrainingdata'] = 'Export training data';
$string['getpredictionsresultscli'] = 'Results using {$a->name} (id: {$a->id}) course duration splitting';
$string['getpredictionsresults'] = 'Results using {$a->name} course duration splitting';
$string['invalidprediction'] = 'Invalid to get predictions';
$string['invalidtraining'] = 'Invalid to train the model';
$string['loginfo'] = 'Log extra info';
+$string['missingmoodleversion'] = 'Imported file does not define a moodle version number';
$string['modelid'] = 'Model ID';
$string['modelinvalidanalysables'] = 'Invalid analysable elements for "{$a}" model';
$string['modelresults'] = '{$a} results';
$string['trainingprocessfinished'] = 'Training process finished';
$string['trainingresults'] = 'Training results';
$string['trainmodels'] = 'Train models';
+$string['versionnotsame'] = 'Imported file was from a different moodle version ({$a->importedversion}) than the current one ({$a->version})';
$string['viewlog'] = 'Log';
$string['weeksenddateautomaticallyset'] = 'End date automatically set based on start date and the number of sections';
$string['weeksenddatedefault'] = 'End date automatically calculated from the course start date.';
*/
require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir . '/dataformatlib.php');
$id = required_param('id', PARAM_INT);
$action = required_param('action', PARAM_ALPHANUMEXT);
case 'disable':
$title = get_string('disable');
break;
- case 'export':
- $title = get_string('export', 'tool_analytics');
+ case 'exportdata':
+ $title = get_string('exporttrainingdata', 'tool_analytics');
+ break;
+ case 'exportmodel':
+ $title = get_string('exportmodel', 'tool_analytics');
break;
case 'clear':
$title = get_string('clearpredictions', 'tool_analytics');
echo $renderer->render_table($modellogstable);
break;
- case 'export':
+ case 'exportdata':
if ($model->is_static() || !$model->is_trained()) {
throw new moodle_exception('errornoexport', 'tool_analytics');
send_file($file, $filename, null, 0, false, true);
break;
+ case 'exportmodel':
+
+ if (!$model->is_static() && $model->get_indicators() && !empty($model->timesplitting)) {
+ throw new moodle_exception('errornoexportconfg', 'tool_analytics');
+ }
+ $downloadfilename = 'model-config.' . $model->get_id() . '.' . time() . '.json';
+ $modelconfig = $model->export_as_json();
+ make_temp_directory('analyticsexport');
+ $tempfilename = $CFG->tempdir .'/analyticsexport/'. md5(sesskey() . microtime() . $downloadfilename);
+ if (!file_put_contents($tempfilename, $modelconfig)) {
+ print_error('cannotcreatetempdir');
+ }
+ @header("Content-type: text/json; charset=UTF-8");
+ send_temp_file($tempfilename, $downloadfilename);
+ break;
+
case 'clear':
confirm_sesskey();
$ADMIN->add('analytics', new admin_externalpage('analyticmodels', get_string('analyticmodels', 'tool_analytics'),
"$CFG->wwwroot/$CFG->admin/tool/analytics/index.php", 'moodle/analytics:managemodels'));
+$ADMIN->add('analytics', new admin_externalpage('analyticsmodelimport', get_string('analyticsimportmodel', 'tool_analytics'),
+ "$CFG->wwwroot/$CFG->admin/tool/analytics/importmodel.php", 'moodle/analytics:managemodels'));
return $model;
}
+ /**
+ * Creates a new model from json configuration.
+ *
+ * @param string $json json data.
+ * @return \core_analytics\model
+ */
+ public static function create_from_json($jsondata) {
+
+ \core_analytics\manager::check_can_manage_models();
+ if (empty($jsondata) || !isset($jsondata->target) || !isset($jsondata->indicators) || !isset($jsondata->timesplitting)) {
+ throw new \coding_exception("invalid json data");
+ }
+
+ // Target.
+ $target = $jsondata->target;
+ if (!class_exists($target)) {
+ throw new \moodle_exception('classdoesnotexist', 'tool_analytics', $target);
+ }
+ $target = \core_analytics\manager::get_target($target);
+
+ // Indicators.
+ $indicators = [];
+ foreach($jsondata->indicators as $indicator) {
+ if (!class_exists($indicator)) {
+ throw new \moodle_exception('classdoesnotexist', 'tool_analytics', $indicator);
+ }
+ $indicators[] = \core_analytics\manager::get_indicator($indicator);
+ }
+
+ // Timesplitting.
+ $timesplitting = $jsondata->timesplitting;
+ if (!class_exists($timesplitting)) {
+ throw new \moodle_exception('classdoesnotexist', 'tool_analytics', $timesplitting);
+ }
+
+ return self::create($target, $indicators, $timesplitting);
+ }
+
/**
* Does this model exist?
*
return $data;
}
+ /**
+ * Exports the model data as JSON.
+ *
+ * @return string JSON encoded data.
+ */
+ public function export_as_json() {
+ global $CFG;
+
+ $data = new \stdClass();
+ $data->target = $this->get_target()->get_id();
+
+
+ if ($timesplitting = $this->get_time_splitting()) {
+ $data->timesplitting = $timesplitting->get_id();
+ } else {
+ // We don't want to allow models without timesplitting to be exported.
+ throw new \moodle_exception('errornotimesplittings', 'analytics');
+ }
+
+ $data->indicators = [];
+ foreach ($this->get_indicators() as $indicator) {
+ $data->indicators[] = $indicator->get_id();
+ }
+ $data->moodleversion = $CFG->version;
+ return json_encode($data);
+ }
+
/**
* Returns the model logs data.
*
$this->assertLessThanOrEqual(2, $DB->count_records('analytics_used_analysables', $params));
}
+ /**
+ * Test export_as_json() API.
+ */
+ public function test_export_as_json() {
+ global $CFG;
+ $this->resetAfterTest(true);
+
+ $this->model->enable('\core\analytics\time_splitting\quarters');
+ $obj = json_decode($this->model->export_as_json());
+ $this->assertSame($CFG->version, $obj->moodleversion);
+ $this->assertSame($this->modelobj->target, $obj->target);
+ $this->assertSame(json_decode($this->modelobj->indicators), $obj->indicators);
+ $this->assertSame($this->modelobj->timesplitting, $obj->timesplitting);
+ }
+
+ /**
+ * Test export_from_json() API.
+ */
+ public function test_create_from_json() {
+ global $CFG;
+ $this->resetAfterTest(true);
+
+ $this->model->enable('\core\analytics\time_splitting\quarters');
+ $json = $this->model->export_as_json();
+ $obj = \core_analytics\model::create_from_json(json_decode($json))->get_model_obj();
+ $this->assertSame($this->modelobj->target, $obj->target);
+ $this->assertSame($this->modelobj->indicators, $obj->indicators);
+ $this->assertSame($this->modelobj->timesplitting, $obj->timesplitting);
+ }
+
/**
* Generates a model log record.
*/