diff options
Diffstat (limited to 'assets/js/lopolisc.js')
-rw-r--r-- | assets/js/lopolisc.js | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/assets/js/lopolisc.js b/assets/js/lopolisc.js new file mode 100644 index 0000000..dfd9ff6 --- /dev/null +++ b/assets/js/lopolisc.js @@ -0,0 +1,433 @@ +function getStringBetween(string, start, end) { + return string.split(start).pop().split(end)[0]; +} + +const LOPOLIS_URL = "https://lopolis.gimb.tk/"; +const LOPOLISC_ERR_NET = "LOPOLSIC NETWORK ERROR (ajax error)"; +const LOPOLISC_ERR_NET_POSTBACK_GET = "LOPOLISC NETWORK ERROR (ajax error) "+ + "in postback GET"; +const LOPOLISC_ERR_LOGIN = "LOPOLISC LOGIN ERROR"; +const LOPOLISC_ERR_NET_POSTBACK_POST = "LOPOLISC NETWORK ERROR (ajax error) "+ + "in postback POST"; +const LOPOLISC_ERR_NET_POSTBACK_POST_IN_POSTBACK = "LOPOLISC NETWORK ERROR $$$"; +const LOPOLISC_ERR_NOTAPPLIED = "LOPOLISC DATA NOT APPLIED ERROR"; +const LOPOLISC_SIGNATURE = "lopolisc.js neuradni API - anton<at>sijanec.eu"; +const LOPOLISC_ERR_OUT_OF_RETRIES = "LOPOLISC ERROR NI VEČ POSKUSOV!"; +class lopolisc { + + constructor() { + } + + parseAndPost(inputHTML, userParams, formId = null, useDiffAction = null) { + return new Promise((resolve, reject) => { + let parser = new DOMParser(); + let parsed = parser.parseFromString(inputHTML, "text/html"); + + var form; + if (formId == null) { + form = parsed.getElementsByTagName("form")[0]; + } else { + form = parsed.getElementById(formId); + } + + var params = {}; + var otherParams = $(form).serializeArray(); + for (const input of otherParams) { + if (!(input.name in params)) { + params[input.name] = input.value; // so we don't overwrite existing values + } + } + + for (const [key, value] of Object.entries(userParams)) { // neki me je + params[key] = value; // zajebaval, pa sem tkole naredu - še enkrat + } // prepišemo vse, kar je v params, z uporabniškimi parametri + // POPRAVEK PO 2 min debugganja: ne, nič ni bilo narobe, pozabil sem + // passat dataToSend v postback(), passal sem {} :facepalm: </notetoself> + var action; + if (useDiffAction == null || useDiffAction == false) { + action = new URL($(form).attr("action"), LOPOLIS_URL); // absolute == relative + base + } else { + action = useDiffAction; + } + + params["programska-oprema"] = LOPOLISC_SIGNATURE; + $.ajax({ + xhrFields: { + withCredentials: true + }, + crossDomain: true, + url: action, + cache: false, + type: "POST", + data: params, + dataType: "text", + maxRetries: 3, + success: (postData, textStatus, xhr) => { + resolve({data: postData, textStatus: textStatus, code: xhr.status}); + }, + error: () => { + reject(new Error(LOPOLISC_ERR_NET_POSTBACK_POST)); + } + }); + }); + } + + postback(getUrl, params = {}, formId = null, useDiffAction = null) { + return new Promise( (resolve, reject) => { + $.ajax({ + xhrFields: { + withCredentials: true + }, + crossDomain: true, + url: getUrl, + cache: false, + type: "GET", + dataType: "html", + success: (data) => { + if (useDiffAction === true) { + useDiffAction = getUrl; + } + this.parseAndPost(data, params, formId, useDiffAction) + .then((value) => { + resolve(value); + }).catch((e)=>{ + reject(new Error(LOPOLISC_ERR_NET_POSTBACK_POST_IN_POSTBACK)); + }); + }, + error: () => { + reject(new Error(LOPOLISC_ERR_NET_POSTBACK_GET)); + } + }); + }); + } + + getUserData() { + return new Promise((resolve, reject)=>{ + $.ajax({ + xhrFields: { + withCredentials: true + }, + crossDomain: true, + url: LOPOLIS_URL+"?MeniID=2", + cache: false, + type: "GET", + dataType: "html", + success: (data) => { + if (data.includes("Dostop ni dovoljen")) { + // console.log(data); + resolve(false); + return; + } + let parser = new DOMParser(); + let p = parser.parseFromString(data, "text/html"); + let uporabnik = { + u: p.getElementsByClassName("obrazecPovdarjen")[0].innerText.trim(), + n: p.getElementsByClassName("obrazecPovdarjen")[1].innerText.trim(), + e: p.getElementById("Email").value + } + resolve(uporabnik); + }, + error: () => { + reject(new Error(LOPOLISC_ERR_NET)); + } + }); + }); + } + + logout() { // you can get pretty race conditiony if you use this wrong! // nah + return new Promise((resolve, reject)=>{ + this.postback(LOPOLIS_URL + "Uporab/Prijava", {}, null, false).then((response) => { // če je true, bo URL, če je false, bo action + resolve(true); // don't bother checking cookies... + }); + }); + } + + login(usernameToLogin, passwordToLogin) { + return new Promise(async function(resolve, reject) { + let l = new lopolisc(); + var uporabnik = await l.getUserData(); + if (uporabnik != false) { + if (uporabnik.u = usernameToLogin) { + resolve(true); + return; + } else { + await this.logout(); + } + } + var dataToSend = { + "Uporabnik": usernameToLogin, + "Geslo": passwordToLogin, + "OsveziURL": "https://pornhub.com/\"; lopolis=\"boljsi od easistenta", + }; + l.postback(LOPOLIS_URL + "Uporab/Prijava", dataToSend, null, true).then((response) => { // če je true, bo URL, če je false, bo action + let parser = new DOMParser(); + let parsed = parser.parseFromString(response.data, "text/html"); + if (parsed.getElementById("divPrijavaOsvezi") != null) { + resolve(true); + } + reject(new Error(LOPOLISC_ERR_LOGIN)); + }); + }); + } + + fetchCheckouts(date_object = null) { + if (date_object == null) { + date_object = new Date(); + } + return new Promise((resolve, reject) => { + var dataToSend = { + "MesecModel.Mesec": String(date_object.getMonth()+1), + "MesecModel.Leto": String(date_object.getFullYear()), + "Ukaz": "" + }; + this.postback(LOPOLIS_URL+"Prehrana/Odjava", dataToSend, null, true).then((response) => { + let parser = new DOMParser(); + let parsed = parser.parseFromString(response.data, "text/html"); + let checkouts = {}; + for (const element of parsed.getElementsByTagName("tbody")[0]. + getElementsByTagName("tr")) { + let date_idx = element.getElementsByTagName("input")[2].value; + checkouts[date_idx] = { + checked/*out*/: element.getElementsByTagName("input")[0].checked, + readonly: element.getElementsByTagName("input")[0].disabled, + // spodaj spremenljivke, ki so potrebne za submit (ne-API) + index: Number(getStringBetween( // string, start, end + element.getElementsByTagName("input")[0].name, "[", "]" + )), + "OsebaModel.ddlOseba": + parsed.getElementsByTagName("option")[0].value, + "OsebaModel.OsebaID": + parsed.getElementById("OsebaModel_OsebaID").value, + "OsebaModel.OsebaTipID": + parsed.getElementById("OsebaModel_OsebaTipID").value, + "OsebaModel.UstanovaID": + parsed.getElementById("OsebaModel_UstanovaID").value, + "MesecModel.Mesec": parsed.getElementById("MesecModel_Mesec").value, + "MesecModel.Leto": parsed.getElementById("MesecModel_Leto").value + } + checkouts[date_idx][element.getElementsByTagName("input")[2].name] = + String(element.getElementsByTagName("input")[2].value); + checkouts[date_idx][element.getElementsByTagName("input")[3].name] = + String(element.getElementsByTagName("input")[3].value); + checkouts[date_idx][element.getElementsByTagName("input")[4].name] = + String(element.getElementsByTagName("input")[4].value); + } + resolve(checkouts); + }); + }); + } + + fetchAllMeals(koliko = 3) { // "vsi" pomeni nas. n mes. (vklj. s tem me.) + return new Promise (async function(resolve, reject) { + let date = new Date(); + let podatki = {}; + while (koliko-- > 0) { + let l = new lopolisc(); // this zajebava, sorry; seja je itak na + let resp = await l.fetchMeals(date); // browserju, ne na objectu. + podatki = {...podatki, ...resp}; + date.setMonth(date.getMonth()+1); // ja, popravi se letnica! + } + resolve(podatki); + }); + } + + + fetchAllCheckouts(koliko = 3) { // "vsi" pomeni nas. n mes. (vklj. s tem me.) + return new Promise (async function(resolve, reject) { + let date = new Date(); + let podatki = {}; + while (koliko-- > 0) { + let l = new lopolisc(); // this zajebava, sorry; seja je itak na + let resp = await l.fetchCheckouts(date); // browserju, ne na objectu. + podatki = {...podatki, ...resp}; + date.setMonth(date.getMonth()+1); // ja, popravi se letnica! + } + resolve(podatki); + }); + } + + setCheckouts(odjava_objects) { + let odjava_objects_sorted = {}; + for (const [odjava_da, odjava_ob] of Object.entries(odjava_objects)) { + let yearmonth_combo = odjava_da.substring(0,7); + if (odjava_objects_sorted[yearmonth_combo] == undefined) { + odjava_objects_sorted[yearmonth_combo] = {}; + } + odjava_objects_sorted[yearmonth_combo][odjava_da] = odjava_ob; + } + if (Object.entries(odjava_objects_sorted).length < 1) { + return false; + } else if (Object.entries(odjava_objects_sorted).length > 1) { + var response; + for (const [ym_combo, odj_ob] of Object.entries(odjava_objects_sorted)) { + response = this.setCheckouts(odj_ob); + } + return response; // napake so itak exceptioni, promisov ne potrebujemo! + } // else: samo en mesec podatkov imamo, let's go! + return new Promise((resolve, reject) => { + var dataToSend = { "Ukaz": "Shrani" }; + for (const [odjava_da, odjava_object] of Object.entries(odjava_objects)) { + for (const [index, property] of Object.entries(odjava_object)) { + dataToSend[index] = property; + } + dataToSend["OdjavaItems["+odjava_object.index+"].CheckOut"] = + String(odjava_object.checked); + } // now we have some excess values, who cares (index, readonly, checked) + this.postback(LOPOLIS_URL+"Prehrana/Odjava", dataToSend, null, true). + then( (response) => { + let parser = new DOMParser(); + let parsed = parser.parseFromString(response.data, "text/html"); + for (const [od_date, odjava_object] of Object.entries(odjava_objects)) { + if (!(parsed.getElementById("OdjavaItems_"+odjava_object.index+"__CheckOut").checked == odjava_object.checked)) { + reject(LOPOLISC_ERR_NOTAPPLIED); + } + } + resolve(true); + }); + }); + } + + fetchMeals(date_object = null, retried = 3) { // retried je interni parameter + if (date_object == null) { + date_object = new Date(); + } + return new Promise((resolve, reject) => { + var meals = {}; + var dataToSend = { + "Ukaz": "", + "MesecModel.Mesec": String(date_object.getMonth()+1), + "API-METODA": "fetchMeals", + "MesecModel.Leto": String(date_object.getFullYear()) + } + this.postback(LOPOLIS_URL+"?MeniID=78",dataToSend,"form1",false). + then((response) => { + let parser = new DOMParser(); + let parsed = parser.parseFromString(response.data, "text/html"); + for (const element of parsed.getElementsByTagName("tbody")[0]. + getElementsByTagName("tr")) { + let menuoptions = []; + let is_any_selected = false; + for (const opt of element.getElementsByTagName("select")[0].options) { + if (opt.value.length > 0 || 1==1) { // tudi prazno opcijo pustimo + menuoptions.push({ + value: opt.value, + text: opt.innerText, + selected: opt.selected + }); + } + if (opt.selected) { + is_any_selected = true; + } + } + if (!is_any_selected) { + menuoptions[0].selected = true; // !!! KAJ GRE LAHKO NAROBE: + // * če je readonly je itak en izbran + // * če je en izbran je itak en izbran + // * če noben ni izbran in je readonly se izbere prazna - okej + // * če noben ni izbran in je readonly se izbere prazna - okej + // prazna (index 0) defaulta na meni 1 (index 1) ampak ne bom tvegal + } + let date_idx = element.getElementsByTagName("input")[0].value; + meals[date_idx] = { // trying to keep same api as rstular's lopolisapi + meal: element.getElementsByTagName("td")[1].innerText.trim(), + "menu-type": element.getElementsByTagName("td")[2].innerText.trim(), + location: element.getElementsByTagName("td")[3].innerText.trim(), + readonly: element.getElementsByTagName("select")[0].disabled, + menu_options: menuoptions, + // properties below are "private" and non-API (undocumented even) + index: Number(getStringBetween( // string, start, end + element.getElementsByTagName("input")[0].name, "[", "]" + )), + "OsebaModel.ddlOseba": + parsed.getElementsByTagName("option")[0].value, + "OsebaModel.OsebaID": + parsed.getElementById("OsebaModel_OsebaID").value, + "OsebaModel.OsebaTipID": + parsed.getElementById("OsebaModel_OsebaTipID").value, + "OsebaModel.UstanovaID": + parsed.getElementById("OsebaModel_UstanovaID").value, + "MesecModel.Mesec": parsed.getElementById("MesecModel_Mesec").value, + "MesecModel.Leto": parsed.getElementById("MesecModel_Leto").value + } + meals[date_idx][element.getElementsByTagName("input")[0].name] = + String(element.getElementsByTagName("input")[0].value); // date + meals[date_idx][element.getElementsByTagName("input")[1].name] = + String(element.getElementsByTagName("input")[1].value); // prijOID? + meals[date_idx][element.getElementsByTagName("input")[2].name] = + String(element.getElementsByTagName("input")[2].value); // readonly + } + resolve(meals); + }).catch((err)=>{ + if (retried <= 0) { + reject(new Error(LOPOLISC_ERR_OUT_OF_RETRIES)); + } else { + resolve(this.fetchMeals(date_object, retried-1)); // retry + } + }); + }); + } + + setMeals(meal_objects) { + let meal_objects_sorted = {}; + for (const [meal_da, meal_ob] of Object.entries(meal_objects)) { + let yearmonth_combo = meal_da.substring(0,7); + if (meal_objects_sorted[yearmonth_combo] == undefined) { + meal_objects_sorted[yearmonth_combo] = {}; + } + meal_objects_sorted[yearmonth_combo][meal_da] = meal_ob; + } + if (Object.entries(meal_objects_sorted).length < 1) { // ni podatkov sploh + return false; + } else if (Object.entries(meal_objects_sorted).length > 1) { + var response; + for (const [ym_combo, meal_ob] of Object.entries(meal_objects_sorted)) { + response = this.setMeals(meal_ob); + } + return response; // itak ne uporabljamo response ampak try{}catch{} except + } // else: samo en mesec podatkov imamo, let's go! + + return new Promise((resolve, reject) => { + var dataToSend = { "Ukaz": "Shrani" }; + for (const [meal_date, meal_object] of Object.entries(meal_objects)) { + for (const [index, property] of Object.entries(meal_object)) { + dataToSend[index] = String(property); + } + for (const menu_option of meal_object.menu_options) { + if (menu_option.selected) { + dataToSend["PrednarocanjeItems["+meal_object.index+ + "].MeniIDSkupinaID"] = menu_option.value; + } + } + } // excess values: meal, menu-type, location, readonly, menu_options + this.postback(LOPOLIS_URL+"Prehrana/Prednarocanje",dataToSend,null,true). + then( (response) => { + let parser = new DOMParser(); + let parsed = parser.parseFromString(response.data, "text/html"); + for (const [meal_date, meal_object] of Object.entries(meal_objects)) { + let selected_value; + for (const menu_option of meal_object.menu_options) { + if (menu_option.selected) { + selected_value = menu_option.value; + } + } + if (!(parsed.getElementById("PrednarocanjeItems_"+meal_object.index+"__MeniIDSkupinaID").selectedOptions[0].value == selected_value)) { + reject(LOPOLISC_ERR_NOTAPPLIED); + } + } + resolve(true); + }); + }); + } + + chooseMenu(meal_object, meal_index) { + for (const menu_option of meal_object.menu_options) { + menu_option.selected = false; + } + meal_object.menu_options[meal_index].selected = true; + return; + } + +} + +// Edited with \ / o _ _ this script is I /\/\ 2020 +// Improved & free \/ I I I I vim-powered my editor \__/ -- sijanec |