mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 14:27:22 +01:00
Merge branch 'MDL-34498-master' of git://github.com/damyon/moodle
This commit is contained in:
commit
4e1ee0bbb5
@ -65,6 +65,10 @@ if ($mform->is_cancelled()) {
|
||||
redirect($returnurl, $warning, null, \core\output\notification::NOTIFY_ERROR);
|
||||
}
|
||||
|
||||
// Try to keep the session alive on this page as it may take some time
|
||||
// before significant interaction happens with the server.
|
||||
\core\session\manager::keepalive();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$mform->display();
|
||||
echo $OUTPUT->footer();
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -496,6 +496,7 @@ $string['sendmessage'] = 'Send message';
|
||||
$string['serverconnection'] = 'Error connecting to the server';
|
||||
$string['servicedonotexist'] = 'The service does not exist';
|
||||
$string['sessionwaiterr'] = 'Timed out while waiting for session lock.<br />Wait for your current requests to finish and try again later.';
|
||||
$string['sessionexpired'] = 'Session expired';
|
||||
$string['sessioncookiesdisable'] = 'Incorrect use of require_key_login() - session cookies must be disabled!';
|
||||
$string['sessiondiskfull'] = 'The session partition is full. It is not possible to log in at this time. Please notify the server administrator.';
|
||||
$string['sessionhandlerproblem'] = 'Session handler is misconfigured';
|
||||
|
@ -802,6 +802,7 @@ $string['existingcoursedeleting'] = 'Existing course, deleting it first';
|
||||
$string['existingcreators'] = 'Existing course creators';
|
||||
$string['existingstudents'] = 'Enrolled students';
|
||||
$string['existingteachers'] = 'Existing teachers';
|
||||
$string['extendsession'] = 'Extend session';
|
||||
$string['expand'] = 'Expand';
|
||||
$string['expandall'] = 'Expand all';
|
||||
$string['expandcategory'] = 'Expand {$a}';
|
||||
@ -1807,7 +1808,8 @@ $string['separateandconnected'] = 'Separate and Connected ways of knowing';
|
||||
$string['separateandconnectedinfo'] = 'The scale based on the theory of separate and connected knowing. This theory describes two different ways that we can evaluate and learn about the things we see and hear.<ul><li><strong>Separate knowers</strong> remain as objective as possible without including feelings and emotions. In a discussion with other people, they like to defend their own ideas, using logic to find holes in opponent\'s ideas.</li><li><strong>Connected knowers</strong> are more sensitive to other people. They are skilled at empathy and tend to listen and ask questions until they feel they can connect and "understand things from their point of view". They learn by trying to share the experiences that led to the knowledge they find in other people.</li></ul>';
|
||||
$string['servererror'] = 'An error occurred whilst communicating with the server';
|
||||
$string['serverlocaltime'] = 'Server\'s local time';
|
||||
$string['sessionforceclean'] = 'As a security precaution, user-generated scripts have been disabled within this session.';
|
||||
$string['sessionforceclean'] = 'As a security precaution, user-generated scripts have been disabled within this session';
|
||||
$string['sessiontimeoutsoon'] = 'Your session is about to timeout. Do you want to extend your current session?';
|
||||
$string['setcategorytheme'] = 'Set category theme';
|
||||
$string['setpassword'] = 'Set password';
|
||||
$string['setpasswordinstructions'] = 'Please enter your new password below, then save changes.';
|
||||
|
@ -29,6 +29,10 @@
|
||||
|
||||
define('AJAX_SCRIPT', true);
|
||||
|
||||
if (!empty($_GET['nosessionupdate'])) {
|
||||
define('NO_SESSION_UPDATE', true);
|
||||
}
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
@ -63,5 +67,4 @@ foreach ($requests as $request) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($responses);
|
||||
|
2
lib/amd/build/ajax.min.js
vendored
2
lib/amd/build/ajax.min.js
vendored
@ -1 +1 @@
|
||||
define(["jquery","core/config","core/log","core/url"],function(a,b,c,d){var e=!1,f=function(a){var b,c,e=this,f=null,g=0;if(a.error)for(;g<e.length;g++)b=e[g],b.deferred.reject(a);else{for(g=0;g<e.length;g++){if(b=e[g],c=a[g],"undefined"==typeof c){f=new Error("missing response");break}if(c.error!==!1){f=c.exception;break}b.deferred.resolve(c.data)}null!==f&&("servicerequireslogin"===f.errorcode?window.location=d.relativeUrl("/login/index.php"):e.forEach(function(a){a.deferred.reject(f)}))}},g=function(a,b,d){var f=this,g=0;for(g=0;g<f.length;g++){var h=f[g];e?(c.error("Page unloaded."),c.error(d)):h.deferred.reject(d)}};return{call:function(c,d,h){a(window).bind("beforeunload",function(){e=!0});var i,j=[],k=[],l=[],m="";for("undefined"==typeof h&&(h=!0),"undefined"==typeof d&&(d=!0),i=0;i<c.length;i++){var n=c[i];j.push({index:i,methodname:n.methodname,args:n.args}),n.deferred=a.Deferred(),k.push(n.deferred.promise()),"undefined"!=typeof n.done&&n.deferred.done(n.done),"undefined"!=typeof n.fail&&n.deferred.fail(n.fail),n.index=i,l.push(n.methodname)}m=l.length<=5?l.sort().join():l.length+"-method-calls",j=JSON.stringify(j);var o={type:"POST",data:j,context:c,dataType:"json",processData:!1,async:d,contentType:"application/json"},p="service.php";h||(p="service-nologin.php");var q=b.wwwroot+"/lib/ajax/"+p+"?sesskey="+b.sesskey+"&info="+m;return d?a.ajax(q,o).done(f).fail(g):(o.success=f,o.error=g,a.ajax(q,o)),k}}});
|
||||
define(["jquery","core/config","core/log","core/url"],function(a,b,c,d){var e=!1,f=function(a){var b,c,e,f=this,g=null,h=0;if(a.error)for(;h<f.length;h++)b=f[h],b.deferred.reject(a);else{for(h=0;h<f.length;h++){if(b=f[h],c=a[h],"undefined"==typeof c){g=new Error("missing response");break}if(c.error!==!1){g=c.exception,e=f[h].nosessionupdate;break}b.deferred.resolve(c.data)}null!==g&&("servicerequireslogin"!==g.errorcode||e?f.forEach(function(a){a.deferred.reject(g)}):window.location=d.relativeUrl("/login/index.php"))}},g=function(a,b,d){var f=this,g=0;for(g=0;g<f.length;g++){var h=f[g];e?(c.error("Page unloaded."),c.error(d)):h.deferred.reject(d)}};return{call:function(c,d,h,i,j){a(window).bind("beforeunload",function(){e=!0});var k,l=[],m=[],n=[],o="";for("undefined"==typeof h&&(h=!0),"undefined"==typeof d&&(d=!0),"undefined"==typeof j&&(j=0),"undefined"==typeof i&&(i=!1),k=0;k<c.length;k++){var p=c[k];l.push({index:k,methodname:p.methodname,args:p.args}),p.nosessionupdate=i,p.deferred=a.Deferred(),m.push(p.deferred.promise()),"undefined"!=typeof p.done&&p.deferred.done(p.done),"undefined"!=typeof p.fail&&p.deferred.fail(p.fail),p.index=k,n.push(p.methodname)}o=n.length<=5?n.sort().join():n.length+"-method-calls",l=JSON.stringify(l);var q={type:"POST",data:l,context:c,dataType:"json",processData:!1,async:d,contentType:"application/json",timeout:j},r="service.php";h||(r="service-nologin.php");var s=b.wwwroot+"/lib/ajax/"+r+"?sesskey="+b.sesskey+"&info="+o;return i&&(s+="&nosessionupdate=true"),d?a.ajax(s,q).done(f).fail(g):(q.success=f,q.error=g,a.ajax(s,q)),m}}});
|
1
lib/amd/build/network.min.js
vendored
Normal file
1
lib/amd/build/network.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core/ajax","core/config","core/notification","core/str"],function(a,b,c,d,e){var f=!1,g=!1,h=0,i=0,j=!1,k=!1,l=1e3*Math.min(c.sessiontimeout/10,600),m=2*l,n=function(){k=!0},o=function(){var a={methodname:"core_session_touch",args:{}};return k?e.get_strings([{key:"sessionexpired",component:"error"},{key:"sessionerroruser",component:"error"}]).then(function(a){return d.alert(a[0],a[1]),!0}).fail(d.exception):b.call([a],!0,!0,!1,i)[0].then(function(){return h>0&&setTimeout(o,h),!0}).fail(function(){d.alert("",j)})},p=function(){var a={methodname:"core_session_time_remaining",args:{}};return k=!1,b.call([a],!0,!0,!0)[0].then(function(a){return!(a.userid<=0)&&(a.timeremaining<0?e.get_strings([{key:"sessionexpired",component:"error"},{key:"sessionerroruser",component:"error"}]).then(function(a){return d.alert(a[0],a[1]),!0}).fail(d.exception):1e3*a.timeremaining<m&&!g?(setTimeout(n,1e3*a.timeremaining),g=!0,e.get_strings([{key:"norecentactivity",component:"moodle"},{key:"sessiontimeoutsoon",component:"moodle"},{key:"extendsession",component:"moodle"},{key:"cancel",component:"moodle"}]).then(function(a){return d.confirm(a[0],a[1],a[2],a[3],function(){return o(),g=!1,setTimeout(p,5*l),!0},function(){g=!1,setTimeout(p,l)}),!0}).fail(d.exception)):setTimeout(p,l),!0)})},q=function(){h>0?setTimeout(o,h):setTimeout(p,5*l)},r=function(){f||(f=!0,q())},s=function(a,b,c){f||(f=!0,h=1e3*a,j=c,i=1e3*b,q())};return{keepalive:s,init:r}});
|
2
lib/amd/build/page_global.min.js
vendored
2
lib/amd/build/page_global.min.js
vendored
@ -1 +1 @@
|
||||
define(["jquery","core/custom_interaction_events","core/str"],function(a,b,c){var d=function(){var d=a("body");b.define(d,[b.events.activate]),d.on(b.events.activate,"[data-show-active-item]",function(b){var d=a(b.target).closest(".dropdown-item"),e=d.closest("[data-show-active-item]");if(d.hasClass("dropdown-item")&&!d.hasClass("active")){var f=e.find(".dropdown-item");f.removeClass("active"),f.removeAttr("aria-current"),e.attr("data-skip-active-class")||d.addClass("active"),d.attr("aria-current",!0);var g=d.text(),h=e.parent().find('[data-toggle="dropdown"]'),i=h.find("[data-active-item-text]");i.length?i.html(g):h.html(g);var j=e.attr("data-active-item-button-aria-label-components");if(j){var k=j.split(",");k.push(g),c.get_string(k[0].trim(),k[1].trim(),k[2].trim()).then(function(a){return h.attr("aria-label",a),a})["catch"](function(){return!1})}}})},e=function(){d()};return{init:e}});
|
||||
define(["jquery","core/custom_interaction_events","core/str","core/network"],function(a,b,c,d){var e=function(){var d=a("body");b.define(d,[b.events.activate]),d.on(b.events.activate,"[data-show-active-item]",function(b){var d=a(b.target).closest(".dropdown-item"),e=d.closest("[data-show-active-item]");if(d.hasClass("dropdown-item")&&!d.hasClass("active")){var f=e.find(".dropdown-item");f.removeClass("active"),f.removeAttr("aria-current"),e.attr("data-skip-active-class")||d.addClass("active"),d.attr("aria-current",!0);var g=d.text(),h=e.parent().find('[data-toggle="dropdown"]'),i=h.find("[data-active-item-text]");i.length?i.html(g):h.html(g);var j=e.attr("data-active-item-button-aria-label-components");if(j){var k=j.split(",");k.push(g),c.get_string(k[0].trim(),k[1].trim(),k[2].trim()).then(function(a){return h.attr("aria-label",a),a})["catch"](function(){return!1})}}})},f=function(){e(),d.init()};return{init:f}});
|
@ -40,11 +40,12 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
*/
|
||||
var requestSuccess = function(responses) {
|
||||
// Call each of the success handlers.
|
||||
var requests = this;
|
||||
var exception = null;
|
||||
var i = 0;
|
||||
var request;
|
||||
var response;
|
||||
var requests = this,
|
||||
exception = null,
|
||||
i = 0,
|
||||
request,
|
||||
response,
|
||||
nosessionupdate;
|
||||
|
||||
if (responses.error) {
|
||||
// There was an error with the request as a whole.
|
||||
@ -69,6 +70,7 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
request.deferred.resolve(response.data);
|
||||
} else {
|
||||
exception = response.exception;
|
||||
nosessionupdate = requests[i].nosessionupdate;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -80,7 +82,7 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
// Something failed, reject the remaining promises.
|
||||
if (exception !== null) {
|
||||
// Redirect to the login page.
|
||||
if (exception.errorcode === "servicerequireslogin") {
|
||||
if (exception.errorcode === "servicerequireslogin" && !nosessionupdate) {
|
||||
window.location = URL.relativeUrl("/login/index.php");
|
||||
} else {
|
||||
requests.forEach(function(request) {
|
||||
@ -132,9 +134,12 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
* If false - this function will call the faster nologin ajax script - but
|
||||
* will fail unless all functions have been marked as 'loginrequired' => false
|
||||
* in services.php
|
||||
* @param {Boolean} nosessionupdate Optional, defaults to false.
|
||||
* If true, the timemodified for the session will not be updated.
|
||||
* @param {Integer} timeout number of milliseconds to wait for a response. Defaults to no limit.
|
||||
* @return {Promise[]} Array of promises that will be resolved when the ajax call returns.
|
||||
*/
|
||||
call: function(requests, async, loginrequired) {
|
||||
call: function(requests, async, loginrequired, nosessionupdate, timeout) {
|
||||
$(window).bind('beforeunload', function() {
|
||||
unloading = true;
|
||||
});
|
||||
@ -150,6 +155,13 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
if (typeof async === "undefined") {
|
||||
async = true;
|
||||
}
|
||||
if (typeof timeout === 'undefined') {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
if (typeof nosessionupdate === "undefined") {
|
||||
nosessionupdate = false;
|
||||
}
|
||||
for (i = 0; i < requests.length; i++) {
|
||||
var request = requests[i];
|
||||
ajaxRequestData.push({
|
||||
@ -157,6 +169,7 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
methodname: request.methodname,
|
||||
args: request.args
|
||||
});
|
||||
request.nosessionupdate = nosessionupdate;
|
||||
request.deferred = $.Deferred();
|
||||
promises.push(request.deferred.promise());
|
||||
// Allow setting done and fail handlers as arguments.
|
||||
@ -185,7 +198,8 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
dataType: 'json',
|
||||
processData: false,
|
||||
async: async,
|
||||
contentType: "application/json"
|
||||
contentType: "application/json",
|
||||
timeout: timeout
|
||||
};
|
||||
|
||||
var script = 'service.php';
|
||||
@ -195,6 +209,10 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
var url = config.wwwroot + '/lib/ajax/' + script +
|
||||
'?sesskey=' + config.sesskey + '&info=' + requestInfo;
|
||||
|
||||
if (nosessionupdate) {
|
||||
url += '&nosessionupdate=true';
|
||||
}
|
||||
|
||||
// Jquery deprecated done and fail with async=false so we need to do this 2 ways.
|
||||
if (async) {
|
||||
$.ajax(url, settings)
|
||||
|
196
lib/amd/src/network.js
Normal file
196
lib/amd/src/network.js
Normal file
@ -0,0 +1,196 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Poll the server to keep the session alive.
|
||||
*
|
||||
* @module core/network
|
||||
* @package core
|
||||
* @copyright 2019 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(['jquery', 'core/ajax', 'core/config', 'core/notification', 'core/str'],
|
||||
function($, Ajax, Config, Notification, Str) {
|
||||
|
||||
var started = false;
|
||||
var warningDisplayed = false;
|
||||
var keepAliveFrequency = 0;
|
||||
var requestTimeout = 0;
|
||||
var keepAliveMessage = false;
|
||||
var sessionTimeout = false;
|
||||
// 1/10 of session timeout, max of 10 minutes.
|
||||
var checkFrequency = Math.min((Config.sessiontimeout / 10), 600) * 1000;
|
||||
// 1/5 of sessiontimeout.
|
||||
var warningLimit = checkFrequency * 2;
|
||||
|
||||
/**
|
||||
* The session time has expired - we can't extend it now.
|
||||
*/
|
||||
var timeoutSessionExpired = function() {
|
||||
sessionTimeout = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ping the server to keep the session alive.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
var touchSession = function() {
|
||||
var request = {
|
||||
methodname: 'core_session_touch',
|
||||
args: { }
|
||||
};
|
||||
|
||||
if (sessionTimeout) {
|
||||
// We timed out before we extended the session.
|
||||
return Str.get_strings([
|
||||
{key: 'sessionexpired', component: 'error'},
|
||||
{key: 'sessionerroruser', component: 'error'}
|
||||
]).then(function(strings) {
|
||||
Notification.alert(
|
||||
strings[0], // Title.
|
||||
strings[1] // Message.
|
||||
);
|
||||
return true;
|
||||
}).fail(Notification.exception);
|
||||
} else {
|
||||
return Ajax.call([request], true, true, false, requestTimeout)[0].then(function() {
|
||||
if (keepAliveFrequency > 0) {
|
||||
setTimeout(touchSession, keepAliveFrequency);
|
||||
}
|
||||
return true;
|
||||
}).fail(function() {
|
||||
Notification.alert('', keepAliveMessage);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ask the server how much time is remaining in this session and
|
||||
* show confirm/cancel notifications if the session is about to run out.
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
var checkSession = function() {
|
||||
var request = {
|
||||
methodname: 'core_session_time_remaining',
|
||||
args: { }
|
||||
};
|
||||
|
||||
sessionTimeout = false;
|
||||
return Ajax.call([request], true, true, true)[0].then(function(args) {
|
||||
if (args.userid <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (args.timeremaining < 0) {
|
||||
Str.get_strings([
|
||||
{key: 'sessionexpired', component: 'error'},
|
||||
{key: 'sessionerroruser', component: 'error'}
|
||||
]).then(function(strings) {
|
||||
Notification.alert(
|
||||
strings[0], // Title.
|
||||
strings[1] // Message.
|
||||
);
|
||||
return true;
|
||||
}).fail(Notification.exception);
|
||||
|
||||
} else if (args.timeremaining * 1000 < warningLimit && !warningDisplayed) {
|
||||
// If we don't extend the session before the timeout - warn.
|
||||
setTimeout(timeoutSessionExpired, args.timeremaining * 1000);
|
||||
warningDisplayed = true;
|
||||
Str.get_strings([
|
||||
{key: 'norecentactivity', component: 'moodle'},
|
||||
{key: 'sessiontimeoutsoon', component: 'moodle'},
|
||||
{key: 'extendsession', component: 'moodle'},
|
||||
{key: 'cancel', component: 'moodle'}
|
||||
]).then(function(strings) {
|
||||
Notification.confirm(
|
||||
strings[0], // Title.
|
||||
strings[1], // Message.
|
||||
strings[2], // Extend session.
|
||||
strings[3], // Cancel.
|
||||
function() {
|
||||
touchSession();
|
||||
warningDisplayed = false;
|
||||
// First wait is half the session timeout.
|
||||
setTimeout(checkSession, checkFrequency * 5);
|
||||
return true;
|
||||
},
|
||||
function() {
|
||||
warningDisplayed = false;
|
||||
setTimeout(checkSession, checkFrequency);
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}).fail(Notification.exception);
|
||||
} else {
|
||||
setTimeout(checkSession, checkFrequency);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
// We do not catch the fails from the above ajax call because they will fail when
|
||||
// we are not logged in - we don't need to take any action then.
|
||||
};
|
||||
|
||||
/**
|
||||
* Start calling a function to check if the session is still alive.
|
||||
*/
|
||||
var start = function() {
|
||||
if (keepAliveFrequency > 0) {
|
||||
setTimeout(touchSession, keepAliveFrequency);
|
||||
} else {
|
||||
// First wait is half the session timeout.
|
||||
setTimeout(checkSession, checkFrequency * 5);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Don't allow more than one of these polling loops in a single page.
|
||||
*/
|
||||
var init = function() {
|
||||
// We only allow one concurrent instance of this checker.
|
||||
if (started) {
|
||||
return;
|
||||
}
|
||||
started = true;
|
||||
|
||||
start();
|
||||
};
|
||||
|
||||
/**
|
||||
* Start polling with more specific values for the frequency, timeout and message.
|
||||
*
|
||||
* @param {number} freq How ofter to poll the server.
|
||||
* @param {number} timeout The time to wait for each request to the server.
|
||||
* @param {string} message The message to display if the session is going to time out.
|
||||
*/
|
||||
var keepalive = function(freq, timeout, message) {
|
||||
// We only allow one concurrent instance of this checker.
|
||||
if (started) {
|
||||
return;
|
||||
}
|
||||
started = true;
|
||||
|
||||
keepAliveFrequency = freq * 1000;
|
||||
keepAliveMessage = message;
|
||||
requestTimeout = timeout * 1000;
|
||||
start();
|
||||
};
|
||||
|
||||
return {
|
||||
keepalive: keepalive,
|
||||
init: init
|
||||
};
|
||||
});
|
@ -26,11 +26,13 @@ define(
|
||||
'jquery',
|
||||
'core/custom_interaction_events',
|
||||
'core/str',
|
||||
'core/network'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
CustomEvents,
|
||||
Str
|
||||
Str,
|
||||
Network
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -127,6 +129,7 @@ function(
|
||||
*/
|
||||
var init = function() {
|
||||
initActionOptionDropdownHandler();
|
||||
Network.init();
|
||||
};
|
||||
|
||||
return {
|
||||
|
95
lib/classes/session/external.php
Normal file
95
lib/classes/session/external.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This class contains a list of webservice functions related to session.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2019 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core\session;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* This class contains a list of webservice functions related to session.
|
||||
*
|
||||
* @copyright 2019 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 2.9
|
||||
*/
|
||||
class external extends \external_api {
|
||||
|
||||
/**
|
||||
* Returns description of touch_session() parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function touch_session_parameters() {
|
||||
return new \external_function_parameters([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the current session.
|
||||
*
|
||||
* @return array the mapping
|
||||
*/
|
||||
public static function touch_session() {
|
||||
\core\session\manager::touch_session(session_id());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of touch_session() result value.
|
||||
*
|
||||
* @return external_description
|
||||
*/
|
||||
public static function touch_session_returns() {
|
||||
return new \external_value(PARAM_BOOL, 'result');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of time_remaining() parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function time_remaining_parameters() {
|
||||
return new \external_function_parameters([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the current session.
|
||||
*
|
||||
* @return array the mapping
|
||||
*/
|
||||
public static function time_remaining() {
|
||||
return \core\session\manager::time_remaining(session_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of touch_session() result value.
|
||||
*
|
||||
* @return external_description
|
||||
*/
|
||||
public static function time_remaining_returns() {
|
||||
return new \external_single_structure(array (
|
||||
'userid' => new \external_value(PARAM_INTEGER, 'The current user id.'),
|
||||
'timeremaining' => new \external_value(PARAM_INTEGER, 'The number of seconds remaining in this session.')
|
||||
));
|
||||
}
|
||||
}
|
@ -364,6 +364,9 @@ class manager {
|
||||
}
|
||||
|
||||
if ($timeout) {
|
||||
if (defined('NO_SESSION_UPDATE') && NO_SESSION_UPDATE) {
|
||||
return;
|
||||
}
|
||||
session_regenerate_id(true);
|
||||
$_SESSION = array();
|
||||
$DB->delete_records('sessions', array('id'=>$record->id));
|
||||
@ -398,7 +401,7 @@ class manager {
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
if ($updated) {
|
||||
if ($updated && (!defined('NO_SESSION_UPDATE') || !NO_SESSION_UPDATE)) {
|
||||
$update->id = $record->id;
|
||||
$DB->update_record('sessions', $update);
|
||||
}
|
||||
@ -632,6 +635,31 @@ class manager {
|
||||
return self::$handler->session_exists($sid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of seconds remaining in the current session.
|
||||
* @param string $sid
|
||||
*/
|
||||
public static function time_remaining($sid) {
|
||||
global $DB, $CFG;
|
||||
|
||||
if (empty($CFG->version)) {
|
||||
// Not installed yet, do not try to access database.
|
||||
return ['userid' => 0, 'timeremaining' => $CFG->sessiontimeout];
|
||||
}
|
||||
|
||||
// Note: add sessions->state checking here if it gets implemented.
|
||||
if (!$record = $DB->get_record('sessions', array('sid' => $sid), 'id, userid, timemodified')) {
|
||||
return ['userid' => 0, 'timeremaining' => $CFG->sessiontimeout];
|
||||
}
|
||||
|
||||
if (empty($record->userid) or isguestuser($record->userid)) {
|
||||
// Ignore guest and not-logged-in timeouts, there is very little risk here.
|
||||
return ['userid' => 0, 'timeremaining' => $CFG->sessiontimeout];
|
||||
} else {
|
||||
return ['userid' => $record->userid, 'timeremaining' => $CFG->sessiontimeout - (time() - $record->timemodified)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake last access for given session, this prevents session timeout.
|
||||
* @param string $sid
|
||||
@ -955,9 +983,10 @@ class manager {
|
||||
* @param string $identifier The string identifier for the message to show on failure.
|
||||
* @param string $component The string component for the message to show on failure.
|
||||
* @param int $frequency The update frequency in seconds.
|
||||
* @param int $timeout The timeout of each request in seconds.
|
||||
* @throws coding_exception IF the frequency is longer than the session lifetime.
|
||||
*/
|
||||
public static function keepalive($identifier = 'sessionerroruser', $component = 'error', $frequency = null) {
|
||||
public static function keepalive($identifier = 'sessionerroruser', $component = 'error', $frequency = null, $timeout = 0) {
|
||||
global $CFG, $PAGE;
|
||||
|
||||
if ($frequency) {
|
||||
@ -966,19 +995,15 @@ class manager {
|
||||
throw new \coding_exception('Keepalive frequency is longer than the session lifespan.');
|
||||
}
|
||||
} else {
|
||||
// A frequency of sessiontimeout / 3 allows for one missed request whilst still preserving the session.
|
||||
$frequency = $CFG->sessiontimeout / 3;
|
||||
// A frequency of sessiontimeout / 10 matches the timeouts in core/network amd module.
|
||||
$frequency = $CFG->sessiontimeout / 10;
|
||||
}
|
||||
|
||||
// Add the session keepalive script to the list of page output requirements.
|
||||
$sessionkeepaliveurl = new \moodle_url('/lib/sessionkeepalive_ajax.php');
|
||||
$PAGE->requires->string_for_js($identifier, $component);
|
||||
$PAGE->requires->yui_module('moodle-core-checknet', 'M.core.checknet.init', array(array(
|
||||
// The JS config takes this is milliseconds rather than seconds.
|
||||
'frequency' => $frequency * 1000,
|
||||
'message' => array($identifier, $component),
|
||||
'uri' => $sessionkeepaliveurl->out(),
|
||||
)));
|
||||
$PAGE->requires->js_call_amd('core/network', 'keepalive', array(
|
||||
$frequency,
|
||||
$timeout,
|
||||
get_string($identifier, $component)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -677,6 +677,22 @@ $functions = array(
|
||||
'loginrequired' => false,
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_session_touch' => array(
|
||||
'classname' => 'core\session\external',
|
||||
'methodname' => 'touch_session',
|
||||
'description' => 'Keep the users session alive',
|
||||
'type' => 'read',
|
||||
'loginrequired' => true,
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_session_time_remaining' => array(
|
||||
'classname' => 'core\session\external',
|
||||
'methodname' => 'time_remaining',
|
||||
'description' => 'Count the seconds remaining in this session',
|
||||
'type' => 'read',
|
||||
'loginrequired' => true,
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_files_get_files' => array(
|
||||
'classname' => 'core_files_external',
|
||||
'methodname' => 'get_files',
|
||||
|
@ -321,6 +321,7 @@ class page_requirements_manager {
|
||||
$this->M_cfg = array(
|
||||
'wwwroot' => $CFG->wwwroot,
|
||||
'sesskey' => sesskey(),
|
||||
'sessiontimeout' => $CFG->sessiontimeout,
|
||||
'themerev' => theme_get_revision(),
|
||||
'slasharguments' => (int)(!empty($CFG->slasharguments)),
|
||||
'theme' => $page->theme->name,
|
||||
|
@ -1,36 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Ensure that session is kept alive.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @package core
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('AJAX_SCRIPT', true);
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
|
||||
// Require the session key - want to make sure that this isn't called
|
||||
// maliciously to keep a session alive longer than intended.
|
||||
if (!confirm_sesskey()) {
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
print_error('invalidsesskey');
|
||||
}
|
||||
|
||||
// Update the session.
|
||||
\core\session\manager::touch_session(session_id());
|
@ -1,6 +1,9 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.8 ===
|
||||
* The yui checknet module is removed. Call \core\session\manager::keepalive instead.
|
||||
|
||||
=== 3.7 ===
|
||||
* Nodes in the navigation api can have labels for each group. See set/get_collectionlabel().
|
||||
* The method core_user::is_real_user() now returns false for userid = 0 parameter
|
||||
|
@ -1 +0,0 @@
|
||||
1
|
@ -1,220 +0,0 @@
|
||||
YUI.add('moodle-core-checknet', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* A utility to check whether the connection to the Moodle server is still
|
||||
* active.
|
||||
*
|
||||
* @module moodle-core-checknet
|
||||
* @package core
|
||||
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @main moodle-core-checknet
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace M.core
|
||||
* @class checknet
|
||||
*/
|
||||
|
||||
function CheckNet() {
|
||||
CheckNet.superclass.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Y.extend(CheckNet, Y.Base, {
|
||||
/**
|
||||
* Zero-based count of alerts displayed.
|
||||
*
|
||||
* @property _alertCount
|
||||
* @type Number
|
||||
* @private
|
||||
* @default 0
|
||||
*/
|
||||
_alertCount: 0,
|
||||
|
||||
/**
|
||||
* A link to the warning dialogue.
|
||||
*
|
||||
* @property _alertDialogue
|
||||
* @type M.core.dialogue
|
||||
* @private
|
||||
* @default null
|
||||
*/
|
||||
_alertDialogue: null,
|
||||
|
||||
/**
|
||||
* Setup the checking mechanism.
|
||||
*
|
||||
* @method initializer
|
||||
*/
|
||||
initializer: function() {
|
||||
// Perform our first check.
|
||||
this._scheduleCheck();
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a check of the checknet file.
|
||||
*
|
||||
* @method _scheduleCheck
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_scheduleCheck: function() {
|
||||
// Schedule the next check after five seconds.
|
||||
Y.later(this.get('frequency'), this, this._performCheck);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform an immediate check of the checknet file.
|
||||
*
|
||||
* @method _performCheck
|
||||
* @private
|
||||
*/
|
||||
_performCheck: function() {
|
||||
Y.io(this.get('uri'), {
|
||||
data: {
|
||||
// Add the session key.
|
||||
sesskey: M.cfg.sesskey,
|
||||
// Add a query string to prevent older versions of IE from using the cache.
|
||||
time: new Date().getTime()
|
||||
},
|
||||
timeout: this.get('timeout'),
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Expires': '-1'
|
||||
},
|
||||
context: this,
|
||||
on: {
|
||||
complete: function(tid, response) {
|
||||
// Check for failure conditions.
|
||||
// We check for a valid status here because if the user is moving away from the page at the time we
|
||||
// run this callback we do not want to display the error.
|
||||
if (response && typeof response.status !== "undefined") {
|
||||
var code = parseInt(response.status, 10);
|
||||
|
||||
if (code === 200) {
|
||||
// This is a valid attempt - clear any existing warning dialogue and destroy it.
|
||||
if (this._alertDialogue) {
|
||||
this._alertDialogue.destroy();
|
||||
this._alertDialogue = null;
|
||||
}
|
||||
} else if (code >= 300 && code <= 399) {
|
||||
// This is a cached status - warn developers, but otherwise ignore.
|
||||
Y.log("A cached copy of the checknet status file was returned so it's reliablity cannot be guaranteed",
|
||||
'warn',
|
||||
'moodle-mod_scorm-checknet');
|
||||
} else {
|
||||
if (this._alertDialogue === null || this._alertDialogue.get('destroyed')) {
|
||||
// Only create a new dialogue if it isn't already displayed.
|
||||
this._alertDialogue = new M.core.alert({
|
||||
message: M.util.get_string.apply(this, this.get('message'))
|
||||
});
|
||||
} else {
|
||||
this._alertDialogue.show();
|
||||
}
|
||||
this._alertCount++;
|
||||
}
|
||||
}
|
||||
// If max alert not modified in args, check indefinitely.
|
||||
// Once max alert count iteration is reached, stop checking.
|
||||
if (this.get('maxalerts') === -1 || (this.get('maxalerts') - 1) >= this._alertCount) {
|
||||
// Start the next check.
|
||||
this._scheduleCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, {
|
||||
NAME: 'checkNet',
|
||||
ATTRS: {
|
||||
/**
|
||||
* The file to check access against.
|
||||
*
|
||||
* @attribute uri
|
||||
* @type String
|
||||
* @default M.cfg.wwwroot + '/lib/yui/build/moodle-core-checknet/assets/checknet.txt'
|
||||
*/
|
||||
uri: {
|
||||
value: M.cfg.wwwroot + '/lib/yui/build/moodle-core-checknet/assets/checknet.txt'
|
||||
},
|
||||
|
||||
/**
|
||||
* The timeout (in milliseconds) before the checker should give up and display a warning.
|
||||
*
|
||||
* @attribute timeout
|
||||
* @type Number
|
||||
* @value 4000
|
||||
*/
|
||||
timeout: {
|
||||
value: 4000
|
||||
},
|
||||
|
||||
/**
|
||||
* The frequency (in milliseconds) that checks should be run.
|
||||
* A new check is not begun until the previous check has completed.
|
||||
*
|
||||
* @attribute frequency
|
||||
* @writeOnce
|
||||
* @type Number
|
||||
* @value 10000
|
||||
*/
|
||||
frequency: {
|
||||
value: 10000
|
||||
},
|
||||
|
||||
/**
|
||||
* The message which should be displayed upon a test failure.
|
||||
*
|
||||
* The array values are passed directly to M.util.get_string() and arguments should match accordingly.
|
||||
*
|
||||
* @attribute message
|
||||
* @type Array
|
||||
* @value [
|
||||
* 'networkdropped',
|
||||
* 'moodle'
|
||||
* ]
|
||||
*/
|
||||
message: {
|
||||
value: [
|
||||
'networkdropped',
|
||||
'moodle'
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* Maxiumum count (not zero-based) of alerts to display for a single page load.
|
||||
*
|
||||
* @attribute maxalerts
|
||||
* @type Number
|
||||
* @value -1
|
||||
*/
|
||||
maxalerts: {
|
||||
value: -1
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
M.core = M.core || {};
|
||||
M.core.checknet = M.core.checknet || {};
|
||||
M.core.checknet.init = function(config) {
|
||||
return new CheckNet(config);
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base-base", "moodle-core-notification-alert", "io-base"]});
|
@ -1 +0,0 @@
|
||||
YUI.add("moodle-core-checknet",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}e.extend(n,e.Base,{_alertCount:0,_alertDialogue:null,initializer:function(){this._scheduleCheck()},_scheduleCheck:function(){return e.later(this.get("frequency"),this,this._performCheck),this},_performCheck:function(){e.io(this.get("uri"),{data:{sesskey:M.cfg.sesskey,time:(new Date).getTime()},timeout:this.get("timeout"),headers:{"Cache-Control":"no-cache",Expires:"-1"},context:this,on:{complete:function(e,t){if(t&&typeof t.status!="undefined"){var n=parseInt(t.status,10);n===200?this._alertDialogue&&(this._alertDialogue.destroy(),this._alertDialogue=null):n>=300&&n<=399||(this._alertDialogue===null||this._alertDialogue.get("destroyed")?this._alertDialogue=new M.core.alert({message:M.util.get_string.apply(this,this.get("message"))}):this._alertDialogue.show(),this._alertCount++)}(this.get("maxalerts")===-1||this.get("maxalerts")-1>=this._alertCount)&&this._scheduleCheck()}}})}},{NAME:"checkNet",ATTRS:{uri:{value:M.cfg.wwwroot+"/lib/yui/build/moodle-core-checknet/assets/checknet.txt"},timeout:{value:4e3},frequency:{value:1e4},message:{value:["networkdropped","moodle"]},maxalerts:{value:-1}}}),M.core=M.core||{},M.core.checknet=M.core.checknet||{},M.core.checknet.init=function(e){return new n(e)}},"@VERSION@",{requires:["base-base","moodle-core-notification-alert","io-base"]});
|
@ -1,217 +0,0 @@
|
||||
YUI.add('moodle-core-checknet', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* A utility to check whether the connection to the Moodle server is still
|
||||
* active.
|
||||
*
|
||||
* @module moodle-core-checknet
|
||||
* @package core
|
||||
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @main moodle-core-checknet
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace M.core
|
||||
* @class checknet
|
||||
*/
|
||||
|
||||
function CheckNet() {
|
||||
CheckNet.superclass.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Y.extend(CheckNet, Y.Base, {
|
||||
/**
|
||||
* Zero-based count of alerts displayed.
|
||||
*
|
||||
* @property _alertCount
|
||||
* @type Number
|
||||
* @private
|
||||
* @default 0
|
||||
*/
|
||||
_alertCount: 0,
|
||||
|
||||
/**
|
||||
* A link to the warning dialogue.
|
||||
*
|
||||
* @property _alertDialogue
|
||||
* @type M.core.dialogue
|
||||
* @private
|
||||
* @default null
|
||||
*/
|
||||
_alertDialogue: null,
|
||||
|
||||
/**
|
||||
* Setup the checking mechanism.
|
||||
*
|
||||
* @method initializer
|
||||
*/
|
||||
initializer: function() {
|
||||
// Perform our first check.
|
||||
this._scheduleCheck();
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a check of the checknet file.
|
||||
*
|
||||
* @method _scheduleCheck
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_scheduleCheck: function() {
|
||||
// Schedule the next check after five seconds.
|
||||
Y.later(this.get('frequency'), this, this._performCheck);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform an immediate check of the checknet file.
|
||||
*
|
||||
* @method _performCheck
|
||||
* @private
|
||||
*/
|
||||
_performCheck: function() {
|
||||
Y.io(this.get('uri'), {
|
||||
data: {
|
||||
// Add the session key.
|
||||
sesskey: M.cfg.sesskey,
|
||||
// Add a query string to prevent older versions of IE from using the cache.
|
||||
time: new Date().getTime()
|
||||
},
|
||||
timeout: this.get('timeout'),
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Expires': '-1'
|
||||
},
|
||||
context: this,
|
||||
on: {
|
||||
complete: function(tid, response) {
|
||||
// Check for failure conditions.
|
||||
// We check for a valid status here because if the user is moving away from the page at the time we
|
||||
// run this callback we do not want to display the error.
|
||||
if (response && typeof response.status !== "undefined") {
|
||||
var code = parseInt(response.status, 10);
|
||||
|
||||
if (code === 200) {
|
||||
// This is a valid attempt - clear any existing warning dialogue and destroy it.
|
||||
if (this._alertDialogue) {
|
||||
this._alertDialogue.destroy();
|
||||
this._alertDialogue = null;
|
||||
}
|
||||
} else if (code >= 300 && code <= 399) {
|
||||
// This is a cached status - warn developers, but otherwise ignore.
|
||||
} else {
|
||||
if (this._alertDialogue === null || this._alertDialogue.get('destroyed')) {
|
||||
// Only create a new dialogue if it isn't already displayed.
|
||||
this._alertDialogue = new M.core.alert({
|
||||
message: M.util.get_string.apply(this, this.get('message'))
|
||||
});
|
||||
} else {
|
||||
this._alertDialogue.show();
|
||||
}
|
||||
this._alertCount++;
|
||||
}
|
||||
}
|
||||
// If max alert not modified in args, check indefinitely.
|
||||
// Once max alert count iteration is reached, stop checking.
|
||||
if (this.get('maxalerts') === -1 || (this.get('maxalerts') - 1) >= this._alertCount) {
|
||||
// Start the next check.
|
||||
this._scheduleCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, {
|
||||
NAME: 'checkNet',
|
||||
ATTRS: {
|
||||
/**
|
||||
* The file to check access against.
|
||||
*
|
||||
* @attribute uri
|
||||
* @type String
|
||||
* @default M.cfg.wwwroot + '/lib/yui/build/moodle-core-checknet/assets/checknet.txt'
|
||||
*/
|
||||
uri: {
|
||||
value: M.cfg.wwwroot + '/lib/yui/build/moodle-core-checknet/assets/checknet.txt'
|
||||
},
|
||||
|
||||
/**
|
||||
* The timeout (in milliseconds) before the checker should give up and display a warning.
|
||||
*
|
||||
* @attribute timeout
|
||||
* @type Number
|
||||
* @value 4000
|
||||
*/
|
||||
timeout: {
|
||||
value: 4000
|
||||
},
|
||||
|
||||
/**
|
||||
* The frequency (in milliseconds) that checks should be run.
|
||||
* A new check is not begun until the previous check has completed.
|
||||
*
|
||||
* @attribute frequency
|
||||
* @writeOnce
|
||||
* @type Number
|
||||
* @value 10000
|
||||
*/
|
||||
frequency: {
|
||||
value: 10000
|
||||
},
|
||||
|
||||
/**
|
||||
* The message which should be displayed upon a test failure.
|
||||
*
|
||||
* The array values are passed directly to M.util.get_string() and arguments should match accordingly.
|
||||
*
|
||||
* @attribute message
|
||||
* @type Array
|
||||
* @value [
|
||||
* 'networkdropped',
|
||||
* 'moodle'
|
||||
* ]
|
||||
*/
|
||||
message: {
|
||||
value: [
|
||||
'networkdropped',
|
||||
'moodle'
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* Maxiumum count (not zero-based) of alerts to display for a single page load.
|
||||
*
|
||||
* @attribute maxalerts
|
||||
* @type Number
|
||||
* @value -1
|
||||
*/
|
||||
maxalerts: {
|
||||
value: -1
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
M.core = M.core || {};
|
||||
M.core.checknet = M.core.checknet || {};
|
||||
M.core.checknet.init = function(config) {
|
||||
return new CheckNet(config);
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base-base", "moodle-core-notification-alert", "io-base"]});
|
@ -1 +0,0 @@
|
||||
1
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "moodle-core-checknet",
|
||||
"builds": {
|
||||
"moodle-core-checknet": {
|
||||
"jsfiles": [
|
||||
"checknet.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
215
lib/yui/src/checknet/js/checknet.js
vendored
215
lib/yui/src/checknet/js/checknet.js
vendored
@ -1,215 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* A utility to check whether the connection to the Moodle server is still
|
||||
* active.
|
||||
*
|
||||
* @module moodle-core-checknet
|
||||
* @package core
|
||||
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @main moodle-core-checknet
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace M.core
|
||||
* @class checknet
|
||||
*/
|
||||
|
||||
function CheckNet() {
|
||||
CheckNet.superclass.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Y.extend(CheckNet, Y.Base, {
|
||||
/**
|
||||
* Zero-based count of alerts displayed.
|
||||
*
|
||||
* @property _alertCount
|
||||
* @type Number
|
||||
* @private
|
||||
* @default 0
|
||||
*/
|
||||
_alertCount: 0,
|
||||
|
||||
/**
|
||||
* A link to the warning dialogue.
|
||||
*
|
||||
* @property _alertDialogue
|
||||
* @type M.core.dialogue
|
||||
* @private
|
||||
* @default null
|
||||
*/
|
||||
_alertDialogue: null,
|
||||
|
||||
/**
|
||||
* Setup the checking mechanism.
|
||||
*
|
||||
* @method initializer
|
||||
*/
|
||||
initializer: function() {
|
||||
// Perform our first check.
|
||||
this._scheduleCheck();
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a check of the checknet file.
|
||||
*
|
||||
* @method _scheduleCheck
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_scheduleCheck: function() {
|
||||
// Schedule the next check after five seconds.
|
||||
Y.later(this.get('frequency'), this, this._performCheck);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform an immediate check of the checknet file.
|
||||
*
|
||||
* @method _performCheck
|
||||
* @private
|
||||
*/
|
||||
_performCheck: function() {
|
||||
Y.io(this.get('uri'), {
|
||||
data: {
|
||||
// Add the session key.
|
||||
sesskey: M.cfg.sesskey,
|
||||
// Add a query string to prevent older versions of IE from using the cache.
|
||||
time: new Date().getTime()
|
||||
},
|
||||
timeout: this.get('timeout'),
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Expires': '-1'
|
||||
},
|
||||
context: this,
|
||||
on: {
|
||||
complete: function(tid, response) {
|
||||
// Check for failure conditions.
|
||||
// We check for a valid status here because if the user is moving away from the page at the time we
|
||||
// run this callback we do not want to display the error.
|
||||
if (response && typeof response.status !== "undefined") {
|
||||
var code = parseInt(response.status, 10);
|
||||
|
||||
if (code === 200) {
|
||||
// This is a valid attempt - clear any existing warning dialogue and destroy it.
|
||||
if (this._alertDialogue) {
|
||||
this._alertDialogue.destroy();
|
||||
this._alertDialogue = null;
|
||||
}
|
||||
} else if (code >= 300 && code <= 399) {
|
||||
// This is a cached status - warn developers, but otherwise ignore.
|
||||
Y.log("A cached copy of the checknet status file was returned so it's reliablity cannot be guaranteed",
|
||||
'warn',
|
||||
'moodle-mod_scorm-checknet');
|
||||
} else {
|
||||
if (this._alertDialogue === null || this._alertDialogue.get('destroyed')) {
|
||||
// Only create a new dialogue if it isn't already displayed.
|
||||
this._alertDialogue = new M.core.alert({
|
||||
message: M.util.get_string.apply(this, this.get('message'))
|
||||
});
|
||||
} else {
|
||||
this._alertDialogue.show();
|
||||
}
|
||||
this._alertCount++;
|
||||
}
|
||||
}
|
||||
// If max alert not modified in args, check indefinitely.
|
||||
// Once max alert count iteration is reached, stop checking.
|
||||
if (this.get('maxalerts') === -1 || (this.get('maxalerts') - 1) >= this._alertCount) {
|
||||
// Start the next check.
|
||||
this._scheduleCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, {
|
||||
NAME: 'checkNet',
|
||||
ATTRS: {
|
||||
/**
|
||||
* The file to check access against.
|
||||
*
|
||||
* @attribute uri
|
||||
* @type String
|
||||
* @default M.cfg.wwwroot + '/lib/yui/build/moodle-core-checknet/assets/checknet.txt'
|
||||
*/
|
||||
uri: {
|
||||
value: M.cfg.wwwroot + '/lib/yui/build/moodle-core-checknet/assets/checknet.txt'
|
||||
},
|
||||
|
||||
/**
|
||||
* The timeout (in milliseconds) before the checker should give up and display a warning.
|
||||
*
|
||||
* @attribute timeout
|
||||
* @type Number
|
||||
* @value 4000
|
||||
*/
|
||||
timeout: {
|
||||
value: 4000
|
||||
},
|
||||
|
||||
/**
|
||||
* The frequency (in milliseconds) that checks should be run.
|
||||
* A new check is not begun until the previous check has completed.
|
||||
*
|
||||
* @attribute frequency
|
||||
* @writeOnce
|
||||
* @type Number
|
||||
* @value 10000
|
||||
*/
|
||||
frequency: {
|
||||
value: 10000
|
||||
},
|
||||
|
||||
/**
|
||||
* The message which should be displayed upon a test failure.
|
||||
*
|
||||
* The array values are passed directly to M.util.get_string() and arguments should match accordingly.
|
||||
*
|
||||
* @attribute message
|
||||
* @type Array
|
||||
* @value [
|
||||
* 'networkdropped',
|
||||
* 'moodle'
|
||||
* ]
|
||||
*/
|
||||
message: {
|
||||
value: [
|
||||
'networkdropped',
|
||||
'moodle'
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* Maxiumum count (not zero-based) of alerts to display for a single page load.
|
||||
*
|
||||
* @attribute maxalerts
|
||||
* @type Number
|
||||
* @value -1
|
||||
*/
|
||||
maxalerts: {
|
||||
value: -1
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
M.core = M.core || {};
|
||||
M.core.checknet = M.core.checknet || {};
|
||||
M.core.checknet.init = function(config) {
|
||||
return new CheckNet(config);
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"moodle-core-checknet": {
|
||||
"requires": [
|
||||
"base-base",
|
||||
"moodle-core-notification-alert",
|
||||
"io-base"
|
||||
]
|
||||
}
|
||||
}
|
@ -282,16 +282,9 @@ if (file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.php'))
|
||||
include_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_12.php');
|
||||
}
|
||||
|
||||
// Add the checknet system to keep checking for a connection.
|
||||
$PAGE->requires->string_for_js('networkdropped', 'mod_scorm');
|
||||
// Build arguments to send to checknet JS.
|
||||
$args = array(
|
||||
'message' => array('networkdropped', 'mod_scorm'),
|
||||
'frequency' => 30000, // Frequency of network check.
|
||||
'timeout' => 10000, // Timeout of network check.
|
||||
'maxalerts' => 1 // Max number of alerts to be thrown.
|
||||
);
|
||||
$PAGE->requires->yui_module('moodle-core-checknet', 'M.core.checknet.init', array($args));
|
||||
// Add the keepalive system to keep checking for a connection.
|
||||
\core\session\manager::keepalive('networkdropped', 'mod_scorm', 30, 10);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
// Set the start time of this SCO.
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2019053000.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2019060600.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user