-
- /**
- * COPYRIGHT © 2022 JOHN PEARCEY
- * All rights reserved
- */
-
- /**
- * The last nonce we just got from the server
- */
- var g_svr_nonce = [];
-
- /**
- * Every 10secs, we get the state of the backup list from the server. This is so that we can keep the front end up-to-date
- * for the user. I'm sure that there are better ways with modern HTML5 but polling is easy and the application is not
- * time critical. This is sufficient.
- */
- var g_bu_list_state = [];
-
- /**
- * This var g_stack_pages contains the app navigation pages in order. The top most page being the
- * current page. So, to go back, you would remove the top most page and navigate to the new top page.
- */
- var g_stack_pages = [];
-
- function clear_page_state(){
- g_bu_list_state = [];
- g_stack_pages = [];
- }
-
- function push_page( pagename ){
- g_stack_pages.push( pagename );
- }
-
- /**
- * Pops the current page off the stack and returns the penultimate one.
- */
- function back_page( ){
- g_stack_pages.pop( );
- return g_stack_pages[g_stack_pages.length - 1];
- }
-
- function index_onload(){
- update_bu_state( false );
- set_main_content( true );
- }
-
- function update_bu_state( bCheckPage = true ){
-
- setTimeout( () => {
- update_bu_state();
- }, 10000);
-
- if(bCheckPage){
- //console.log( "update_bu_state pages:", g_stack_pages );
- if( g_stack_pages[g_stack_pages.length - 1] != 'backup-list' ) return;
- }
-
- //console.log( "update_bu_state polling" );
-
- map_params = new Map();
- map_params.set('action', 'backup-list-state' );
-
- postData( "post_handler.php", function( success, data, m ){
-
- if(data[1][0]=='login'){
- console.log( 'Cannot get backup-list-state: Not logged in' );
- return;
- }
-
- let new_state = data[1][1];
-
- //console.log( 'backup-list-state' + new_state );
-
- if( g_bu_list_state.length == 0 ){
- //just store the new state
- g_bu_list_state = new_state;
- return;
- }
-
- //compare the two arrays, if different length, then refresh the UI.
- if( g_bu_list_state.length != new_state.length ){
- g_bu_list_state = new_state;
- set_main_content( false );
- return;
- }
-
- //check each row in turn
- let bFound = false;
- for( j=0; j<g_bu_list_state.length; j++){
- curr_state_j = g_bu_list_state[j];
- bFound = false;
-
- //console.log("looking for ID = " + curr_state_j[0] );
-
- for( i=0; i<new_state.length; i++){
-
- new_state_i = new_state[i];
- //console.log("compare with", new_state_i );
-
-
- if( new_state_i[0] == curr_state_j[0]){
- bFound = (new_state_i[1] == curr_state_j[1]);
- break;
- }
- }
- if(!bFound){
- //at least one ID or value does not match
- g_bu_list_state = new_state;
- set_main_content( false );
- break;
- }
- }
-
- }, map_params );
-
- }
-
-
-
-
- function set_main_content( bPushPage ){
-
- //console.log("3");
-
- map_params = new Map();
- map_params.set('action', 'backup-list' );
-
- postData( "post_handler.php", function( success, data, m ){
-
- if(data[0]!="OK"){
- console.log( data );
- return;
- }
-
- let elem = document.getElementById('page_content');
-
- //display page from server
- [ page_type, elem.innerHTML ] = data[1];
- console.log('set_main_content page_type: ', page_type );
-
- if(page_type=='login'){
- //clear client side data
- clear_page_state();
- g_svr_nonce = data[1][2];
- return;
- }
-
- if(bPushPage) push_page('backup-list');
-
- }, map_params );
-
- }
-
- /**
- * Button clicked and we require a new page from the server to be placed in the page_content area.
- * instr(uction) is usually the page name except where a 'back' navigation is required.
- */
- async function btn_clk_nav( elem, instr, id=0 ){
-
- // instr can now also be a space separated list of instructions
- //we split them out
- instrArr = instr.split(" ");
- instr = instrArr[0];
-
- //noTest
-
- map_params = new Map();
- map_params.set('id', id );
-
- let b_is_db_type = false;
-
- switch(instr){
-
- case 'btn_login':
- if( !valid_btn_login() ) return;
- await set_btn_login( map_params );
- map_params.set('svr_nonce', g_svr_nonce );
- map_params.set('final-page', 'backup-list' );
- navigate_page( instr, map_params, false );
- return;
-
- case 'btn_run_bu':
- bIsBuTest = (instrArr.length==2 && instrArr[1]=='noTest');
- if( bIsBuTest ){
- map_params.set('isTest', 'false' );
- }else{
- map_params.set('isTest', 'true' );
- console.log("running a test backup");
-
- }
- exec_instruction( instr, map_params );
-
- if(!bIsBuTest){
- monitorBuOutput( true, id, -1 );
- }
- return;
-
- case 'delete-bu':
- if( !confirm('Are you sure you wish to delete backup item ' + id ) ) return;
- map_params.set('final-page', 'backup-list' );
- navigate_page( instr, map_params, false );
- return;
-
- case 'btn_edit_shed_bu':
- if( !valid_btn_edit_shed_bu() ) return;
- set_btn_edit_shed_bu( map_params );
- map_params.set('final-page', back_page() ); //server to return previous page (usually backup-list) after processing
- navigate_page( 'edit_shed_bu', map_params, false );
- return;
-
- case 'btn_new_bu_db':
- b_is_db_type=true;
- //drop through
- case 'btn_new_bu_file':
- if( !valid_btn_new_bu( b_is_db_type ) ) return;
- set_btn_new_bu( b_is_db_type, map_params );
- map_params.set('final-page', back_page() ); //server to return previous page (usually backup-list) after processing
- navigate_page( 'new-item-bu', map_params, false );
- return;
-
- case 'btn_edit_bu_db':
- b_is_db_type=true;
- //drop through
- case 'btn_edit_bu_file':
- if( !valid_btn_new_bu( b_is_db_type ) ) return;
- set_btn_new_bu( b_is_db_type, map_params );
- map_params.set('final-page', back_page() ); //server to return previous page (usually backup-list) after processing
- navigate_page( 'edit-item-bu', map_params, false );
- return;
-
- case 'btn_cancel_new_bu':
- case 'btn_cancel':
- navigate_page( back_page(), map_params, false );
- return;
- }
-
- navigate_page( instr, map_params, true );
- }
-
-
- function navigate_page( goto_page, map_params, bPushPage ){
-
- //console.log( 'navigate_page: ', goto_page );
-
- map_params.set('action', goto_page );
- //map_params.set('updateList', JSON.stringify( usrUpdates ) );
-
- postData( "post_handler.php", function( success, data, m ){
-
- if(data[0]!="OK"){
- console.log( data[0], data[1] );
- if(!bPushPage){
- //we need to put back the page that we dropped off or maybe an error page
- //but use goto_page for now
- push_page( goto_page );
- }
- return;
- }
-
- let elem = document.getElementById('page_content');
- [ page_type, elem.innerHTML ] = data[1];
- console.log('navigate_page page_type: ', page_type);
-
- if(page_type=='login'){
- //clear client side data
- clear_page_state();
- g_svr_nonce = data[1][2];
- return;
- }
-
- if(page_type=='authenticated'){
- elem = document.getElementById('anc_login');
- elem.innerHTML="Logout";
- elem.setAttribute("href","post_handler.php?action=logout");
- push_page( map_params.get('final-page') );
- return;
- }
-
- if(bPushPage) push_page( goto_page );
-
- }, map_params );
-
- }
-
- function setTextAreaFromArray( elem, arr ){
- elem.value = arr.toString().replaceAll(',', "\r\n" );
- }
-
- function exec_instruction( instr, map_params ){
-
- console.log( 'exec_instruction: ', instr );
- let id = map_params.get('id');
-
- map_params.set('action', instr );
- //map_params.set('updateList', JSON.stringify( usrUpdates ) );
-
- postData( "post_handler.php", function( success, data, m ){
-
- if(data[0]!="OK"){
- console.log( data );
- return;
- }
-
- bu_result = data[1][0]; //was it ok or err?
-
- switch(instr){
- case 'btn_run_bu':
-
- if(bu_result!='ok:'){
- //latest msg contains similar format as used by the server rpc layer
- console.log("odd message: " + bu_result );
- console.log( data );
- return;
- }
- bu_status = data[1][1]; //extra info
-
- if(bu_status=='running'){
-
- // is it a test run? - by rights, I should send back the 'test' flag
- let elem = document.getElementById( "ta_testoutput" );
- if(elem==null){
- //not a test - set the tick
- let elem = document.getElementById( "td_run_" + id );
- elem.innerHTML = "<img id=\"td_run_\"" + id + " src=\"img/green-tick.png\">";
-
- //ensure the state map is also adjusted
- for( j=0; j<g_bu_list_state.length; j++){
- if(g_bu_list_state[j][0]==id){
- g_bu_list_state[j][1] = 1;
- }
- }
-
- }else{
- //test run
- setTextAreaFromArray( elem, bu_result + " " + bu_status );
- }
-
- }else{
-
- console.log("unknown message: " + bu_status );
- console.log( data );
- }
-
- break;
-
- default:
- console.log( data[1] );
-
- }
-
- }, map_params );
-
- }
-
- function monitorBuOutput( bMonitor, buid, from_line_num ){
-
- if(from_line_num==-1){
- //first call, just set the timer and give some time for the test to kick off
- setTimeout( () => {
- monitorBuOutput(true, buid, 0);
- }, 1000);
- return ;
- }
-
- console.log("Fetch output from line: " + from_line_num );
-
- let e_ta_testoutput = document.getElementById( "ta_testoutput" );
- if(e_ta_testoutput==null){
- // page gone (should terminate server open file?)
- return;
- }
-
- let map_params = new Map();
- map_params.set('action', 'bu-test-file-lines' );
- map_params.set('buid', buid );
- map_params.set('from-line-num', from_line_num );
-
- postData( "post_handler.php", function( success, data, m ){
- //console.log( data );
- let cnt=0;
- let rtm_msg = data[1][cnt++]; //'f:bu-test-file-lines'
- let line_count = data[1][cnt++];
- let line_data = '';
- if(line_count>0){
- line_data = data[1][cnt++];
- }
-
- e_ta_testoutput = document.getElementById( "ta_testoutput" );
- if(e_ta_testoutput==null){
- // page gone (should terminate server open file?)
- return;
- }
-
- if(line_count>0){
- //setTextAreaFromArray( e_ta_testoutput, line_data );
- e_ta_testoutput.value += "\n" + line_data;
-
- setTimeout( () => {
- monitorBuOutput(true, buid, line_count + from_line_num );
- }, 1000);
- return ;
- }else{
- console.log("No more lines to fetch" );
- }
-
- }, map_params);
-
- }
-
-
- function valid_btn_login(){
-
- let login_name = document.getElementById('login_name').value;
- if(login_name=='') {
- alert("Please enter your login name");
- return false;
- }
-
- let login_pwd = document.getElementById('login_pwd').value;
- if(login_pwd=='') {
- alert("Please enter your password");
- return false;
- }
- return true;
- }
-
- /**
- * Collect data from login form
- */
- async function set_btn_login( map_params ){
-
- let raw_pwd = document.getElementById('login_pwd').value;
-
- console.log("pwd = "+raw_pwd);
- console.log("nonce = " + g_svr_nonce);
-
- const pwd_hash = await getHash256(raw_pwd+g_svr_nonce);
- map_params.set( 'username', document.getElementById('login_name').value );
- map_params.set( 'password', pwd_hash );
- }
-
- async function getHash256(message) {
- //https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
- const encoder = new TextEncoder();
- const data = encoder.encode(message);
- const hashBuffer = await window.crypto.subtle.digest("SHA-256", data);
- const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
- const hashHex = hashArray
- .map((b) => b.toString(16).padStart(2, "0"))
- .join(""); // convert bytes to hex string
- return hashHex;
- }
-
- /**
- * Validate the form for a new backup entry
- * b_is_db_type is true for DB entry and false for file entry.
- */
- function valid_btn_new_bu( b_is_db_type ){
- return true;
- }
-
- /**
- * Collect the form data together.
- * b_is_db_type is true for DB entry and false for file entry.
- */
- function set_btn_new_bu( b_is_db_type, map_params ){
-
- map_params.set( 'new_bu_is_dbType', b_is_db_type?1:0 );
- map_params.set( 'new_bu_name', document.getElementById('new_bu_name').value );
- map_params.set( 'new_bu_source', document.getElementById('new_bu_source').value );
- map_params.set( 'new_bu_dest', document.getElementById('new_bu_dest').value );
- if(b_is_db_type){
- console.log("Setting DB params username=" + document.getElementById('db_usr_name').value );
- map_params.set( 'db_usr_name', document.getElementById('db_usr_name').value );
- map_params.set( 'db_usr_pwd', document.getElementById('db_usr_pwd').value );
- }else{
- console.log("Setting File params");
- map_params.set( 'new_bu_exf', document.getElementById('new_bu_exf').value );
- }
- }
-
- /**
- * Validate the form for the backup scheduling page
- */
- function valid_btn_edit_shed_bu(){
-
- sched_date = document.getElementById('sched_date').value;
- if(sched_date=='') {
- alert("Please choose a date");
- return false;
- }
-
- sched_time = document.getElementById('sched_time').value;
- if(sched_time=='') {
- alert("Please choose a time");
- return false;
- }
-
- let dt_chosen = new Date( sched_date + 'T' + sched_time + ':00Z');
- let now = new Date();
-
- if(dt_chosen<=now){
- alert("Please choose a time in the future, not the past: ", dt_chosen, now );
- return false;
- }
-
- console.log("dates: ", dt_chosen, now );
-
- return true;
- }
-
- /**
- * Collect the form data together for the backup scheduling page
- */
- function set_btn_edit_shed_bu( map_params ){
-
- map_params.set( 'sched_date', document.getElementById('sched_date').value );
- map_params.set( 'sched_time', document.getElementById('sched_time').value );
-
- switch(document.querySelector('input[name="sched_period"]:checked').id){
- case 'sched_ip_daily':
- map_params.set( 'sched_period', 'D' );
- break;
-
- case 'sched_ip_weekly':
- map_params.set( 'sched_period', 'W' );
- break;
-
- case 'sched_ip_monthly':
- map_params.set( 'sched_period', 'M' );
- break;
-
- case 'sched_ip_none':
- default:
- map_params.set( 'sched_period', 'N' );
- }
-
-
- }
-