Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
davidszkiba committed Nov 18, 2024
1 parent 02df042 commit b257f38
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 8 deletions.
96 changes: 96 additions & 0 deletions amd/src/syncscale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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/>.

/*
* @package local_catquiz
* @copyright Wunderbyte GmbH <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

import {get_string as getString} from 'core/str';
import Ajax from 'core/ajax';
import Notification from 'core/notification';

const SELECTORS = {
FORMCONTAINER: '#lcq_select_context_form',
CALCULATEBUTTON: '#sync_button'
};
/**
* Add event listener to buttons.
*/
export const init = () => {

const syncButton = document.querySelector(SELECTORS.SYNCBUTTON);
// Hardcoded values for testing.
const centralurl = 'https://192.168.56.6';
const wstoken = '2f36a8dc27525b97a93e50186035d49e';
const scalelabel = 'simulation';

const contextId = parseInt(calculateButton.dataset.contextid);
calculateButton.onclick = () => {
updateParameters(contextId);
};

const updateParameters = async(contextid) => {
const urlParams = new URLSearchParams(window.location.search);
const catscaleid = urlParams.get('scaleid');

// Fallback if the translation can not be loaded
let errorMessage = 'Something went wrong';
try {
errorMessage = await getString('somethingwentwrong', 'local_catquiz');
} catch (error) {
// We already have a fallback message, nothing to do here.
}
Ajax.call([{
methodname: 'local_catquiz_update_parameters',
args: {contextid, catscaleid},
done: async function(res) {
if (res.success) {
disableButton();
// Fallback if the translation can not be loaded
let successMessage = 'Recalculation was scheduled';
try {
successMessage = await getString('recalculationscheduled', 'local_catquiz');
} catch (error) {
// We already have a fallback message, nothing to do here.
}

Notification.addNotification({
message: successMessage,
type: 'success'
});
} else {
disableButton();
Notification.addNotification({
message: errorMessage,
type: 'danger'
});
}
},
fail: () => {
disableButton();
Notification.addNotification({
message: errorMessage,
type: 'danger'
});
},
}]);
};

const disableButton = () => {
document.querySelector(SELECTORS.CALCULATEBUTTON).setAttribute('disabled', true);
};
};
205 changes: 205 additions & 0 deletions classes/external/client_fetch_parameters.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
<?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/>.

defined('MOODLE_INTERNAL') || die();

require_once($CFG->libdir . '/externallib.php');
require_once($CFG->libdir . '/filelib.php');

namespace local_catquiz\external;

use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
use core_external\external_multiple_structure;
use local_catquiz\catscale;

/**
* This class contains a list of webservice functions related to the catquiz Module by Wunderbyte.
*
* @package local_catquiz
* @copyright 2024 Wunderbyte GmbH
* @author David Szkiba
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class fetch_parameters extends external_api {
/**
* Returns description of method parameters
* @return external_function_parameters
*/
public static function execute_parameters() {
return new external_function_parameters([
'centralurl' => new external_value(PARAM_URL, 'URL of central instance'),
'token' => new external_value(PARAM_TEXT, 'Web service token'),
'scalelabel' => new external_value(PARAM_TEXT, 'Label of the scale to sync'),
]);
}

/**
* Returns description of method return values
* @return external_single_structure
*/
public static function execute_returns() {
return new external_single_structure([
'status' => new external_value(PARAM_BOOL, 'Status of the sync'),
'duration' => new external_value(PARAM_FLOAT, 'Duration in seconds'),
'synced' => new external_value(PARAM_INT, 'Number of parameters synced'),
'errors' => new external_value(PARAM_INT, 'Number of errors encountered'),
'message' => new external_value(PARAM_TEXT, 'Status message'),
'warnings' => new external_multiple_structure(
new external_single_structure([
'item' => new external_value(PARAM_TEXT, 'Item identifier'),
'warning' => new external_value(PARAM_TEXT, 'Warning message'),
])
),
]);
}

/**
* Fetches and synchronizes item parameters from a central instance
*
* @param string $centralurl URL of the central Moodle instance
* @param string $token Web service token for authentication
* @param string $scalelabel Label of the scale to synchronize
* @return array Returns status information about the sync operation including:
* - status (bool): Whether any parameters were successfully synced
* - duration (float): Time taken for the operation in seconds
* - synced (int): Number of parameters successfully synchronized
* - errors (int): Number of errors encountered
* - message (string): Status message describing the operation
* - warnings (array): List of specific warnings/errors encountered
* @throws \invalid_parameter_exception If parameters are invalid
*/
public static function execute(string $centralurl, string $token, string $scalelabel) {
global $DB;

$params = self::validate_parameters(self::execute_parameters(), [
'centralurl' => $centralurl,
'token' => $token,
'scalelabel' => $scalelabel,
]);

$starttime = microtime(true);
$warnings = [];
$stored = 0;
$errors = 0;

// Get the local scale.
$scale = $DB->get_record('local_catquiz_catscales', ['label' => $params['scalelabel']], '*', MUST_EXIST);

// Call central instance.
$serverurl = rtrim($params['centralurl'], '/') . '/webservice/rest/server.php';
$wsparams = [
'wstoken' => $params['token'],
'wsfunction' => 'local_catquiz_fetch_item_parameters',
'moodlewsrestformat' => 'json',
'scalelabel' => $params['scalelabel'],
];
$CFG->curlsecurityblockedhosts = ''; // TODO: Remove.
$curl = new \curl();
$curl->setopt(['CURLOPT_SSL_VERIFYPEER' => false, 'CURLOPT_SSL_VERIFYHOST' => false]);
$response = $curl->post($serverurl, $wsparams);
unset($CFG->curlsecurityblockedhosts);
$result = json_decode($response);

if (!$result || isset($result->exception)) {
return [
'status' => false,
'duration' => 0,
'synced' => 0,
'errors' => 1,
'message' => $result->message ?? 'Invalid response from server',
'warnings' => [],
];
}

// Create a mapping of catscale labels to IDs.
$scalemapping = [];
$catscaleids = [$scale->id, ...catscale::get_subscale_ids($scale->id)];
[$inscalesql, $inscaleparams] = $DB->get_in_or_equal($catscaleids, SQL_PARAMS_NAMED, 'scaleid');

$sql = <<<SQL
SELECT *
FROM {local_catquiz_catscales} lcs
WHERE lcs.id $inscalesql
SQL;

$scalerecords = $DB->get_records_sql($sql, $inscaleparams);
foreach ($scalerecords as $s) {
$scalemapping[$s->label] = $s->id;
}

// Create new context.
$source = "Fetch from " . parse_url($params['centralurl'], PHP_URL_HOST);
$newcontext = \local_catquiz\data\dataapi::create_new_context_for_scale(
$scale->id,
$scale->name,
$source,
false
);

// Process and store parameters.
foreach ($result->parameters as $param) {
$questionid = \local_catquiz\remote\hash\question_hasher::get_questionid_from_hash($param->questionhash);
if (!$questionid) {
$warnings[] = ['item' => $param->questionhash, 'warning' => 'Question not found locally'];
$errors++;
continue;
}

try {
$itemrecord = new \stdClass();
$itemrecord->componentid = $questionid;
$itemrecord->componentname = 'question';
$itemrecord->catscaleid = $scale->id;
$itemrecord->contextid = $newcontext->id;
$itemrecord->status = LOCAL_CATQUIZ_TESTITEM_STATUS_ACTIVE;
$itemid = $DB->insert_record('local_catquiz_items', $itemrecord);

$paramrecord = new \stdClass();
$paramrecord->itemid = $itemid;
$paramrecord->componentid = $questionid;
$paramrecord->componentname = 'question';
$paramrecord->contextid = $newcontext->id;
$paramrecord->model = $param->model;
$paramrecord->difficulty = $param->difficulty;
$paramrecord->discrimination = $param->discrimination;
$paramrecord->status = $param->status;
$paramrecord->json = $param->json;

$itemparam = \local_catquiz\local\model\model_item_param::from_record($paramrecord);
$itemparam->save();
$stored++;
} catch (\Exception $e) {
debugging('Error storing parameter: ' . $e->getMessage(), DEBUG_DEVELOPER);
$warnings[] = ['item' => $param->questionhash, 'warning' => $e->getMessage()];
$errors++;
}
}

$duration = microtime(true) - $starttime;

return [
'status' => $stored > 0,
'duration' => round($duration, 2),
'synced' => $stored,
'errors' => $errors,
'message' => $stored > 0 ? "Successfully synced $stored parameters" : 'No parameters were synced',
'warnings' => $warnings,
];
}
}
6 changes: 1 addition & 5 deletions classes/external/fetch_item_parameters.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,7 @@ public static function execute($scalelabel, $questionhashes = [], $models = [])
// Get all relevant scale IDs (parent scale and subscales)
$catscaleids = [$scale->id, ...catscale::get_subscale_ids($scale->id)];
// Get the latest context for this scale.
$contextid = catscale::get_context_id($scale->id);
if (!$contextid) {
throw new moodle_exception('nocontextfound', 'local_catquiz');
}

$contextid = $scale->contextid;
// Get all questions assigned to this scale.
[$inscalesql, $inscaleparams] = $DB->get_in_or_equal($catscaleids, SQL_PARAMS_NAMED, 'scaleid');

Expand Down
4 changes: 2 additions & 2 deletions db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ function xmldb_local_catquiz_upgrade($oldversion) {
// This is a bit unconventional. The table already exists with old, long
// names on a moodle instance that supports longer table names but can't be
// created on a different instance that has stricter naming rules.
if ($oldversion < 2024110802) {
if ($oldversion < 2024111804) {
// Check if old table exists first.
if ($dbman->table_exists('local_catquiz_question_hashmap')) {
// Rename the table.
Expand Down Expand Up @@ -1054,7 +1054,7 @@ function xmldb_local_catquiz_upgrade($oldversion) {
}
}

upgrade_plugin_savepoint(true, 2024110802, 'local', 'catquiz');
upgrade_plugin_savepoint(true, 2024111804, 'local', 'catquiz');
}


Expand Down
3 changes: 3 additions & 0 deletions templates/catscalemanager/catscales.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
require(['local_catquiz/calculatescales'], function(init) {
init.init();
});
require(['local_catquiz/syncscale'], function(init) {
init.init();
});
});
{{/js}}
{{/scaledetailview}}
Expand Down
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

$plugin->component = 'local_catquiz';
$plugin->release = '1.1.1';
$plugin->version = 2024111802;
$plugin->version = 2024111804;
$plugin->requires = 2022041900;
$plugin->maturity = MATURITY_STABLE;
$plugin->dependencies = [
Expand Down

0 comments on commit b257f38

Please sign in to comment.