fixing some issues with redirects.

This commit is contained in:
Stefan Midjich 2016-12-14 16:37:32 +01:00
parent d895b36263
commit 143e31e932
5 changed files with 58 additions and 38 deletions

View File

@ -8,8 +8,9 @@ debug=True
redis_host=127.0.0.1 redis_host=127.0.0.1
redis_port=6379 redis_port=6379
plugin_ttl=120 plugin_timeout=180
# Can specify an alternate webpage for the portal
index_page=portalindex index_page=portalindex
[logging] [logging]

View File

@ -1,7 +1,7 @@
# Captiveportal web application using Bottle.py # Captiveportal web application using Bottle.py
import json import json
from pprint import pprint from pprint import pprint as pp
from uuid import UUID from uuid import UUID
from importlib import import_module from importlib import import_module
@ -128,12 +128,17 @@ def dispatch_plugins():
)) ))
continue continue
# Let plugin run for 30 more seconds than the defined plugin_timeout
# because that value is also used by the JS code to poll the job
# status so we don't want rq to kill the job before JS has timed out.
plugin_timeout = config.getint('portal', 'plugin_timeout')+30
# Run plugin.run() # Run plugin.run()
try: try:
plugin_job = Q.enqueue( plugin_job = Q.enqueue(
plugin_module.run, plugin_module.run,
arg, arg,
ttl=config.getint('portal', 'plugin_ttl') timeout=plugin_timeout
) )
except Exception as e: except Exception as e:
l.warn('{plugin}: {error}'.format( l.warn('{plugin}: {error}'.format(
@ -166,7 +171,7 @@ app.router.add_filter('uuid', uuid_filter)
def portalindex(): def portalindex():
return template( return template(
config.get('portal', 'index_page'), config.get('portal', 'index_page'),
plugin_ttl=config.get('portal', 'plugin_ttl') plugin_timeout=config.getint('portal', 'plugin_timeout')
) )
@ -203,6 +208,7 @@ def job_status(job_id):
'meta': job.meta 'meta': job.meta
} }
return json.dumps(job_data) return json.dumps(job_data)

View File

@ -18,3 +18,7 @@
color: #D8000C; color: #D8000C;
background-color: #FFBABA; background-color: #FFBABA;
} }
#error-box {
display:none;
}

View File

@ -1,11 +1,10 @@
// Captive portal Javascript // Captive portal Javascript
// by Stefan Midjich // by Stefan Midjich @ Cygate AB
//
// //
var debug = true; var debug = true;
var getUrlParameter = function getUrlParameter(sParam) { function getUrlParameter(sParam, default_value) {
var sPageURL = decodeURIComponent(window.location.search.substring(1)), var sPageURL = decodeURIComponent(window.location.search.substring(1)),
sURLVariables = sPageURL.split('&'), sURLVariables = sPageURL.split('&'),
sParameterName, sParameterName,
@ -18,12 +17,15 @@ var getUrlParameter = function getUrlParameter(sParam) {
return sParameterName[1] === undefined ? true : sParameterName[1]; return sParameterName[1] === undefined ? true : sParameterName[1];
} }
} }
};
return default_value;
}
// This function ensures the user gets redirect to the correct destination once // This function ensures the user gets redirect to the correct destination once
// all jobs have succeeded in the portal software. // all jobs have succeeded in the portal software.
function do_success() { function do_success() {
var url = getUrlParameter('url'); var url = getUrlParameter('url', 'www.google.com');
// If url does not start with http the window.location redirect // If url does not start with http the window.location redirect
// won't work. So prefix http to url. // won't work. So prefix http to url.
@ -31,24 +33,30 @@ function do_success() {
url = 'http://'+url; url = 'http://'+url;
} }
console.log('success: '+url); console.log('success: '+url);
$('#error-box').html('<p>If you\'re not automatically redirected open your browser and try any website manually.</p>');
$('#error-box').show();
$('#statusDiv').html('');
$('#approveButton').prop('disabled', false);
// Do something like refresh the window or go to another URL. // Redirect user to the url paramter.
window.location = url; window.location = url;
} }
// Show an error to the user // Show an error to the user
function do_error(message) { function do_error(message) {
console.log('failure: '+message);
$('#approveButton').prop('disabled', false); $('#approveButton').prop('disabled', false);
$('#statusDiv').html('');
$('#error-box').show(); $('#error-box').show();
$('#form-row').hide(); $('#error-box').html('<p>Failed. Reload page and try again or contact support.</p> ');
$('#error-box').append('<p>Failed. Reload page and try again or contact support.</p> ');
if (message) { if (message) {
console.log('server: '+message);
$('#error-box').append('<p>System response: '+message+'</p>'); $('#error-box').append('<p>System response: '+message+'</p>');
} }
} }
// Poll the returned jobs and ensure they all succeed // Poll the returned jobs and ensure they all succeed
function poll_jobs(data) { function poll_jobs(data) {
var promises = []; var promises = [];
@ -67,7 +75,7 @@ function poll_jobs(data) {
} }
promises.push(new Promise(function(resolve, reject) { promises.push(new Promise(function(resolve, reject) {
var maxRun = plugin_ttl/2; var maxRun = plugin_timeout/2;
var timesRun = 0; var timesRun = 0;
// Timer function that polls the API for job results // Timer function that polls the API for job results
@ -83,14 +91,14 @@ function poll_jobs(data) {
console.log(job_result); console.log(job_result);
if(job_result.is_finished) { if(job_result.is_finished) {
console.log('Resolving job: ', job_result.id); console.log('Resolving job: ', job_result);
resolve(job_result); resolve(job_result);
clearTimeout(timer); clearTimeout(timer);
return(true); return(true);
} }
if(job_result.is_failed) { if(job_result.is_failed) {
console.log('Job failed: ', job_result.id); console.log('Job failed: ', job_result);
reject(job_result); reject(job_result);
clearTimeout(timer); clearTimeout(timer);
return(false); return(false);
@ -117,48 +125,46 @@ function poll_jobs(data) {
} }
// Run .all() on promises array until all promises resolve // Run .all() on promises array until all promises resolve
// This is resolve() above.
Promise.all(promises).then(function(result) { Promise.all(promises).then(function(result) {
var success = true; var success = true;
for(var i=0;i<result.length;i++) { for(var i=0;i<result.length;i++) {
console.log('Job result: ', result[i]);
var r = result[i].result; var r = result[i].result;
var m = result[i].meta; var meta = result[i].meta;
if (r.failed && m.mandatory) { if (meta.mandatory) {
do_error(r.error); if (result[i].is_finished && result[i].is_failed) {
success = false; do_error(r.error);
break; success = false;
break;
}
} }
} }
if (success) { if (success) {
// Will hopefully try a redirect until it succeeds. // This is for Steve...
var timer = setInterval(do_success, 2000); // Apple devices don't poll their captiveportal URL,
// so this is for them. Android devices will do their
// own polling and close the wifi-portal before this.
setTimeout(do_success, 30000);
} }
// This is reject() above.
}, function(reason) { }, function(reason) {
do_error(reason); do_error(reason);
}); });
} }
$(document).ready(function() {
$('#error-box').hide();
});
// Submit the form // Submit the form
$('#approveForm').submit(function (event) { $('#approveForm').submit(function (event) {
var api_url = '/approve'; var api_url = '/approve';
event.preventDefault(); event.preventDefault();
$('#error-box').hide();
$('#approveButton').prop('disabled', true);
$('#statusDiv').html('<img src="/static/images/radio.svg" alt="Loading, please wait..." />');
// Had some issues trying to set a background image on the button, so I'm
// just replacing it.
if ($('#approveCheckbox').is(':checked')) { if ($('#approveCheckbox').is(':checked')) {
$('#approveButton').prop('disabled', true);
//$('#approveButton').val('');
$('#approveButton').addClass('button-loading');
//$('#approveButtonDiv').replaceWith('<img src="/static/images/radio.svg" alt="Loading, please wait..." />');
var ajaxReq = $.post(api_url); var ajaxReq = $.post(api_url);
ajaxReq.done(poll_jobs); ajaxReq.done(poll_jobs);

View File

@ -54,6 +54,8 @@
<div class="row"> <div class="row">
<div id="error-box" class="five columns msgbox msgbox-error"> <div id="error-box" class="five columns msgbox msgbox-error">
</div> </div>
<div id="statusDiv">
</div>
</div> </div>
<div id="form-row" class="row"> <div id="form-row" class="row">
@ -64,7 +66,8 @@
</div> </div>
<div id="approveButtonDiv" class="one column u-pull-left"> <div id="approveButtonDiv" class="one column u-pull-left">
<label> <label>
<input id="approveButton" class="button-primary" value="Approve" type="submit"> <button class="button-primary" id="approveButton" type="submit">Approve</button>
<!--<input id="approveButton" class="button-primary" value="Approve" type="submit">-->
</label> </label>
</div> </div>
</div> </div>
@ -73,7 +76,7 @@
</div> </div>
<script> <script>
var plugin_ttl = {{plugin_ttl}}; var plugin_timeout = {{plugin_timeout}};
</script> </script>
<script src="/static/js/jquery-1.12.2.min.js"></script> <script src="/static/js/jquery-1.12.2.min.js"></script>
<script src="/static/js/captiveportal.js"></script> <script src="/static/js/captiveportal.js"></script>