import * as UI from './ui.js'; import { langPack } from './langpack.js'; var waitTokenRenew=false; var tokenCheckSheduled=false; var clockOffset=0; export function loadModule(modPath) { import(modPath).then(function(mod) { mod.load(); }) } export async function sleepMs(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } export function getCorrectedTime() { let localTime=Date.now() / 1000 | 0; let offset = localStorage.getItem("clockOffset"); if (offset==undefined) { offset=0; } return localTime+Number(offset); } // errDict export async function exec(requestType, method , data, onSuccess,noblank,onError,version) { if (typeof(requestType)=='object') { var ref=requestType; requestType=ref.requestType; method=ref.method; data=ref.data; onSuccess=ref.onSuccess; noblank=ref.noblank; onError=ref.onError; version=ref.version; var skipSessionCheck=ref.skipSessionCheck; var xoss=true; } else { var xoss=false; var ref={}; } if (noblank==undefined || noblank==false) { UI.blankerShow(); } if (requestType==undefined) { requestType="GET" } if (requestType=="GET") { data=undefined; } if (version==undefined) { version=2; } if (skipSessionCheck==undefined) { skipSessionCheck=false } if (!isset(method)) { throw("Empty method not allowed"); } var transationStamp=(new Date()).getTime(); while (waitTokenRenew && !skipSessionCheck) { await sleepMs(100); } if (!skipSessionCheck) { await session.check(); } let headers={}; let token=localStorage.getItem("token"); if (token!==null) { headers.Authorization="Token "+token; } //console.log("API Call started: "+requestType+" "+method + " : "+ transationStamp); //console.log("Call token: "+token); return $.ajax({ url: "/api/v"+String(version)+"/"+method, data: JSON.stringify(data), type: requestType, headers: headers, async: ref.async==undefined?true:ref.async, complete: function(data,textStatus,request) { let serverTime=UI.date2stamp(data.getResponseHeader('Date')); let localTime=Date.now() / 1000 | 0; clockOffset=serverTime-localTime; localStorage.setItem("clockOffset", clockOffset); var transationEndStamp=(new Date()).getTime(); // console.log("API Call completed: "+requestType+" "+method + " : " + transationStamp + " : " + (transationEndStamp-transationStamp) + " ms"); if (data.getResponseHeader('X-Fox-Token-Renew') !=null) { session.updateToken(data.getResponseHeader('X-Fox-Token-Renew'),data.getResponseHeader('X-Fox-Token-Expire'),data.getResponseHeader('X-Fox-JWT')); } let rcode=data.status; let rtext=data.statusText; let rdata=data.responseText; try { var jdata=JSON.parse(rdata); } catch(err) { console.log("Unable to parce reply",rdata); rcode=599; rtext="Reply parce failure"; jdata=undefined; } var rv={status: {success: (rcode>=200 && rcode <300), code: rcode, message: rtext} , data: jdata}; if (rv.status.success) { UI.blankerHide(); let ossrv=undefined; if (typeof(onSuccess) == 'function') { ossrv=onSuccess(rv, rtext); } if (xoss && (ossrv!==false)) { UI.showInfoDialog(langPack.core.iface.ok0); } } else { UI.blankerHide(); let rtext2; if (isset(jdata) && isset(jdata.error) && isset(jdata.error.xCode)) { var xCode=jdata.error.xCode; if (isset(ref.errDict) && isset(ref.errDict[xCode])) { rtext=ref.errDict[jdata.error.xCode]; rtext2=rtext; } else { rtext2=rtext; rtext=xCode+" "+rtext; } } else { var xCode=rcode; rtext2=rtext; rtext=xCode+" "+rtext; } if (typeof(onError) == 'function') { onError(rv, {code: xCode, message: rtext2}); } else { if (onError=="blanker") { UI.showError(xCode, rtext2); } else { UI.showInfoDialog({message: rtext, title: langPack.core.iface.err0,dialogName: "apiExecStatus"+transationStamp, closeCallback: ref.onFinal}); } } } }, dataType: "html" }); } export function getFileByToken(token, fileName) { let url='/api/v2/core/file/'+token; const a = document.createElement('a') a.href = url if (fileName != undefined) { a.download=fileName; } document.body.appendChild(a) a.click() document.body.removeChild(a); } function uploadFileToken(file, token){ let formData = new FormData(); formData.append(token, file); fetch('/api/v2/core/file', { method: "POST", body: formData }); } export function uploadFiles(method, filesFieldId, extraFields) { let data={}; if (typeof(extraFields)=='object') { let data=extraFields; } let files = document.getElementById(filesFieldId).files; $.each(files, function(_key, file) { data.fileName=file.name; data.fileSize=file.size; API.exec({ requestType: "POST", method: method, data: data, onSuccess: function(json) { uploadFileToken(file, json.data.Token); return false; } }) }) return; } export class settings { static async load() { if (sessionStorage.getItem("baseSettings")==undefined) { await exec("GET","meta/settings",{},function(json) { sessionStorage.setItem("baseSettings",JSON.stringify(json.data)); },true) } } static get(key) { let settings={}; let userSettings={}; if (sessionStorage.getItem("baseSettings")!=undefined) { settings=JSON.parse(sessionStorage.getItem("baseSettings")); } if (sessionStorage.getItem("userSettings")!=undefined) { settings=JSON.parse(sessionStorage.getItem("userSettings")); } if (userSettings["key"] != undefined) { return userSettings[key] } else { return settings[key] } } } export class auth { static async login(login, password, callback, meta) { if (login==undefined || password==undefined) { throw "Empty credentials not allowed here"; } let payload={}; if (meta!=undefined) { payload=meta; } payload.login=login; payload.password=password; payload.type="WEB"; API.exec("POST", "auth/login",payload, function onSuccess(json) { console.log(json.data) session.open(json.data) if (typeof(callback) == 'function') { callback(json.status.code); } },false,function(json) { if (typeof(callback) == 'function') { callback(json.status.code); } }); } } export class session { static getConfigItem(item) { let user=this.get("user"); if (user && user.config && user.config[item]) { return user.config[item]; } else { return settings.get(item); } } static parseJwt () { let token=localStorage.getItem("jwt"); if (!token) { return null; } let base64Url = token.split('.')[1]; let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); let jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); return JSON.parse(jsonPayload); } static getJwt() { return localStorage.getItem("jwt"); } static sheduleCheck() { //console.log("ScheduleCheck sheduler started"); if (!tokenCheckSheduled) { //console.log("ScheduleCheck sheduler sheduled"); tokenCheckSheduled=true; let token=session.parseJwt(); let dtx=token.exp-token.iat; waitTokenRenew=false; setTimeout(session.check, (dtx*0.25 | 0)*1000, true); } } static async check(sheduled) { //console.log((sheduled===true?"Sheduled":"Regular")+" token check executed") if (sheduled===true) { tokenCheckSheduled=false; } if (waitTokenRenew) { console.log("Token reneq already in progress"); return; } let token = session.parseJwt(); let now=getCorrectedTime(); if (token) { let dtx=token.exp-token.iat; let renew = token.iat+(dtx/2 | 0) if (renew < now) { //console.log ("Token renew started"); waitTokenRenew=true; await API.exec({ skipSessionCheck: true, requestType: "GET", method: "auth/renew", noblank: true, onSuccess: function(json) { //console.log("Token renew success") localStorage.setItem("token",json.data.token); localStorage.setItem("tokenExpire",json.data.expire); localStorage.setItem("jwt",json.data.jwt); waitTokenRenew=false; session.sheduleCheck(); return false; }, onError: function(error) { console.log("Token renew failes with ERROR", error) waitTokenRenew=false; return false } }) } else { //console.log("Token not ready for renew") session.sheduleCheck(); } } } static getLang() { return this.getConfigItem("language"); } static close() { localStorage.removeItem("token"); localStorage.removeItem("tokenExpire"); localStorage.removeItem("jwt"); sessionStorage.removeItem("session"); } static open(data) { localStorage.setItem("token",data.token); localStorage.setItem("tokenExpire",data.expire); localStorage.setItem("jwt",data.jwt); sessionStorage.setItem("session",data.session); } static updateToken(token, tokenExpire, jwt) { localStorage.setItem("token",token); localStorage.setItem("tokenExpire",tokenExpire); localStorage.setItem("jwt",jwt); } static get(key) { if (sessionStorage.getItem("session")==undefined) { return undefined; } return JSON.parse(sessionStorage.getItem("session"))[key]; } static getMenu() { if (session.get("menu") == undefined) { let menu={}; $.each(session.get("modules"),function(mkey,mod) { $.each(mod.menu,function(nkey,nmenu) { nmenu.xmodkey=mod.name; menu[mod.name+"_"+nkey]=nmenu; }); }); return menu; } else { return session.get("menu"); } } static checkAccess(rule, module) { let acls=this.get("acls"); if (module==undefined) { module="core"; } if (acls[module]!=undefined && Object.values(acls[module]).includes(rule)) { return true; } else if (acls[""]!=undefined && acls[""].includes(rule)) { return true; } else if (acls[""]!=undefined && acls[""].includes("isRoot")) { return true; } else { return false; } } static getModInstances() { if (session.get("modInstances") == undefined) { let instances={}; $.each(session.get("modules"),function(key,val) { instances[val.name]=val.instanceOf; }); session.set("modInstances",instances); return instances; } else { return session.get("modInstances"); } } static getModuleByInstance(instance) { return session.getModInstances()[instance]; } static set(key,val) { if (sessionStorage.getItem("session")==undefined) { var xsession={}; } else { var xsession=JSON.parse(sessionStorage.getItem("session")); } xsession[key]=val; sessionStorage.setItem("session",JSON.stringify(xsession)); } static async reload(callback) { sessionStorage.removeItem("session"); this.load(callback); } static async load(callback) { let token=localStorage.getItem("token"); if (token===null) { // session not found session.close(); console.log("Session token not found"); return; } let stamp=new Date(); if ((sessionStorage.getItem("session")!=undefined) && (((stamp.getTime()/1000)-this.get("updated"))