summaryrefslogtreecommitdiffstats
path: root/assets
diff options
context:
space:
mode:
Diffstat (limited to 'assets')
-rw-r--r--assets/js/app.js.bvr1
-rw-r--r--assets/js/lang/bundle.js29
-rw-r--r--assets/js/lopolisc.js433
-rw-r--r--assets/js/meals.js311
-rw-r--r--assets/pages-src/changelog.bvr13
-rw-r--r--assets/pages-src/meals.bvr20
-rw-r--r--assets/pages-src/misc/grading-add-modal.bvr1
-rw-r--r--assets/pages-src/misc/matomo.bvr52
-rw-r--r--assets/pages-src/misc/msg-compose-modal.bvr1
-rw-r--r--assets/pages-src/misc/navigation.bvr4
-rw-r--r--assets/root/sw.js.bvr1
11 files changed, 615 insertions, 251 deletions
diff --git a/assets/js/app.js.bvr b/assets/js/app.js.bvr
index 5441c59..a96ea88 100644
--- a/assets/js/app.js.bvr
+++ b/assets/js/app.js.bvr
@@ -1,4 +1,5 @@
<@?i global@>
+// @begin=html@
const app_version = "<@?g app_version@>";
const previous_commit = "<@?g latest_commit@>";
const BEZIAPP_UPDATE_INTERVAL = 300; // update vsakih 300 sekund
diff --git a/assets/js/lang/bundle.js b/assets/js/lang/bundle.js
index 4e15832..bd0335c 100644
--- a/assets/js/lang/bundle.js
+++ b/assets/js/lang/bundle.js
@@ -18,9 +18,6 @@ async function refreshLangDOM() {
localforage.getItem("chosenLang").then( (value) => {
chosenLang = value;
})
- // localforage.getItem("chosenCapitalize").then( (value) => { // poor unused code
- // chosenCapitalize = value;
- // })
];
await Promise.all(promises_to_runn);
// this could be done nicer. p. s.: lahko bi se uporablil x-s in x-S za razločitev med capitalize in !capitalize queryselectorall ni case sensitive za imena elementov
@@ -58,16 +55,18 @@ async function setLangConfigAndReload() {
window.location.reload();
}
window.addEventListener("DOMContentLoaded", () => {
- localforage.getItem("chosenLang").then( (value) => {
- if(value == null) {
- setLangConfigAndReload();
- } else {
- chosenLang = value;
- }
- });
- refreshLangDOM();
+ find_chosen_lang();
});
+async function find_chosen_lang() {
+ let value = await localforage.getItem("chosenLang");
+ if(value == null) {
+ setLangConfigAndReload();
+ } else {
+ chosenLang = value;
+ }
+ refreshLangDOM();
+}
const capitalize = (s) => {
if (typeof s !== 'string') return ''
@@ -253,6 +252,10 @@ var langstrings = {
mealSet: "meal set! Reload meals to be sure",
selected: "selected",
meal: "meal",
+ checkedOut: "checked out",
+ checkedIn: "checked in",
+ successfulCheckingInOut: "successfully checked in/out",
+ errorCheckingInOut: "failed to check in/out",
// about
version: "version",
authors: "authors",
@@ -461,6 +464,10 @@ var langstrings = {
mealSet: "obrok nastavljen! osvežite obroke in se prepričajte sami",
selected: "izbrano",
meal: "obrok",
+ checkedOut: "odjavljen",
+ checkedIn: "prijavljen",
+ errorCheckingInOut: "prijava/odjava na obrok NI uspela",
+ successfulCheckingInOut: "prijava/odjava na obrok je uspela",
// about
version: "različica",
authors: "avtorji",
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
diff --git a/assets/js/meals.js b/assets/js/meals.js
index 15accdb..1cf1977 100644
--- a/assets/js/meals.js
+++ b/assets/js/meals.js
@@ -1,8 +1,8 @@
-const API_ENDPOINT = "https://lopolis-api.gimb.tk/";
+const API_ENDPOINT = "https://lopolis-api.gimb.tk/"; // unused!
var meals_calendar_obj = null;
var meals_data_global = {};
-
+var checkouts_data_global = {};
function getDateString() { // ne mene gledat, ne vem, kaj je to.
let date = new Date();
@@ -50,105 +50,49 @@ async function getToken(callback, callbackparams = []) {
})
];
await Promise.all(promises_to_run);
-
- $.ajax({
- url: API_ENDPOINT + "gettoken",
- crossDomain: true,
- contentType: "application/json",
- data: JSON.stringify({
- "username": username,
- "password": password
- }),
-
- dataType: "json",
- cache: false,
- type: "POST",
-
- success: (dataauth) => {
- if (dataauth == null || dataauth.error == true) {
- UIAlert(D("authenticationError"), "getToken(): response error or null");
- localforage.setItem("logged_in_lopolis", false).then(function() {
- checkLogin();
- });
- } else if (dataauth.error == false) {
- let empty = {};
- empty.token = dataauth.data;
- let argumentsToCallback = [empty].concat(callbackparams);
- callback(...argumentsToCallback); // poslje token v {token: xxx}
- } else {
- UIAlert(D("authenticationError"), "getToken(): invalid response, no condition met");
- }
- setLoading(false);
- },
- error: () => {
- UIAlert(D("lopolisAPIConnectionError"), "getToken(): AJAX error");
- setLoading(false);
- }
- });
+ try {
+ var lopolisClient = new lopolisc();
+ var response = await lopolisClient.login(username, password);
+ // če response ni true bo itak exception
+ } catch (e) {
+ console.log(e);
+ UIAlert(D("authenticationError"), "getToken(): invalid response, no condition met");
+ await localforage.setItem("logged_in_lopolis", false);
+ return false;
+ }
+ await localforage.setItem("logged_in_lopolis", true);
+ let empty = {};
+ empty.token = {}; // tokenov NI VEČ! old code pa to
+ let argumentsToCallback = [empty].concat(callbackparams);
+ callback(...argumentsToCallback); // poslje token v {token: xxx}
}
async function getMenus(dataauth, callback, callbackparams = []) {
setLoading(true);
- let current_date = new Date();
- // naloži za dva meseca vnaprej (če so zadnji dnevi v mesecu)
- let mealsgathered = {};
- let promises_to_wait_for = [];
- for (let iteration = 1; iteration <= 2; iteration++) {
-
- promises_to_wait_for[iteration] = $.ajax({
- url: API_ENDPOINT + "getmenus",
- crossDomain: true,
- contentType: "application/json",
- data: JSON.stringify({
- "month": current_date.getMonth() + iteration,
- "year": current_date.getFullYear()
- }),
-
- headers: {
- "Authorization": `Bearer ${dataauth.token}`
- },
-
- dataType: "json",
- cache: false,
- type: "POST",
-
- success: (meals) => {
- if (meals == null || meals.error == true) {
- UIAlert(D("errorGettingMenus"), "getMenus(): response error or null");
- setLoading(false);
- localforage.setItem("logged_in_lopolis", false).then(() => {
- checkLogin();
- });
- } else if (meals.error == false) {
- setLoading(false);
- mealsgathered[iteration] = meals;
- } else {
- setLoading(false);
- UIAlert(D("errorUnexpectedResponse"), "getMenus(): invalid response, no condition met");
- }
- },
-
- error: () => {
- setLoading(false);
- UIAlert(D("lopolisAPIConnectionError"), "getMenus(): AJAX error");
- }
- });
- }
-
- await Promise.all(promises_to_wait_for); // javascript is ducking amazing
-
- let allmeals = {};
let passtocallback = {};
-
- for (const [index, monthmeals] of Object.entries(mealsgathered)) { // although this is not very javascripty
- allmeals = mergeDeep(allmeals, monthmeals.data);
+ let allmeals, allcheckouts;
+ let tries = 3;
+ while (true) {
+ try {
+ let lopolisClient = new lopolisc();
+ allmeals = await lopolisClient.fetchAllMeals();
+ allcheckouts = await lopolisClient.fetchAllCheckouts();
+ } catch (e) {
+ console.log(e);
+ UIAlert(D("lopolisAPIConnectionError"), "getMenus(): AJAX error");
+ if (tries-- < 0) {
+ return false;
+ } else {
+ continue;
+ }
+ }
+ break;
}
-
- passtocallback.data = allmeals;
- passtocallback.token = dataauth.token;
+ passtocallback.data = allmeals; // kot po starem apiju so meniji še vedno tu!!
+ passtocallback.checkouts = allcheckouts;
+ passtocallback.token = "tokens-not-used-anymore";
let toBePassed = [passtocallback].concat(callbackparams);
callback(...toBePassed);
-
}
async function loadMeals() {
@@ -158,6 +102,7 @@ async function loadMeals() {
function displayMeals(meals) {
// console.log(JSON.stringify(meals)); // debug // dela!
meals_data_global = meals.data;
+ checkouts_data_global = meals.checkouts;
let transformed_meals = [];
for (const [date, mealzz] of Object.entries(meals.data)) {
let bg_color = "#877F02"; let fg_color = "#FFFFFF";
@@ -165,7 +110,7 @@ function displayMeals(meals) {
let meal_date = new Date(date+"+00:00"); // idk u figure it out. timezones
let meal_object = {
start: meal_date.toISOString().substring(0,10), // zakaj? poglej gradings.js - NUJNO! poglej, če so timezoni v redu! da slučajno ne preskakuje na naslednji dan!
- title: S("meal"),
+ title: mealzz.meal,
id: date,
allDay: true,
backgroundColor: bg_color,
@@ -175,6 +120,7 @@ function displayMeals(meals) {
}
meals_calendar_obj.removeAllEvents();
meals_calendar_obj.addEventSource(transformed_meals);
+ setLoading(false);
return;
}
@@ -188,117 +134,35 @@ function refreshMeals() {
}
function lopolisLogout() {
- localforage.setItem("logged_in_lopolis", false);
- $("#meals-collapsible").html("");
- checkLogin();
+ localforage.setItem("logged_in_lopolis", false).then(()=>{
+ clearMeals();
+ checkLogin();
+ });
}
async function lopolisLogin() {
setLoading(true);
var usernameEl = $("#meals-username");
var passwordEl = $("#meals-password");
- $.ajax({
- url: API_ENDPOINT + "gettoken",
- crossDomain: true,
- contentType: "application/json",
- data: JSON.stringify({
- "username": usernameEl.val(),
- "password": passwordEl.val()
- }),
-
- dataType: "json",
- cache: false,
- type: "POST",
-
- success: async function(data) {
- if (data == null) {
- UIAlert(S("requestForAuthenticationFailed"), "lopolisLogin(): date is is null");
- setLoading(false);
- usernameEl.val("");
- passwordEl.val("");
- } else if (data.error == true) {
- UIAlert(S("loginFailed"), "lopolisLogin(): login failed. data.error is true");
- usernameEl.val("");
- passwordEl.val("");
- setLoading(false);
- } else {
- let promises_to_run = [
- localforage.setItem("logged_in_lopolis", true),
- localforage.setItem("lopolis_username", usernameEl.val()),
- localforage.setItem("lopolis_password", passwordEl.val())
- ];
- await Promise.all(promises_to_run);
- checkLogin();
- UIAlert("Credential match!");
- }
- },
-
- error: () => {
- UIAlert(D("loginError"), "lopolisLogin(): ajax.error");
- setLoading(false);
- }
- });
-}
-
-async function setMenus(currentmeals = 69, toBeSentChoices) { // currentmeals je getMenus response in vsebuje tudi token.
-
- if (currentmeals === 69) {
- getToken(getMenus, [setMenus, toBeSentChoices]);
- return;
+ try {
+ let l = new lopolisc();
+ await l.login(usernameEl.val(), passwordEl.val());
+ } catch (e) {
+ UIAlert(D("loginError"), "lopolisLogin(): ajax.error");
+ setLoading(false);
+ return false;
}
-
- for (const [mealzzdate, mealzz] of Object.entries(currentmeals.data)) {
- if (mealzzdate in toBeSentChoices === false) {
- for (const [mealid, mealdata] of Object.entries(mealzz.menu_options)) {
- // console.log(mealdata);
- if (mealdata.selected == true || mealzz.readonly == true) {
- toBeSentChoices[mealzzdate] = mealdata.value;
- break;
- }
- }
- }
- }
-
- setLoading(true);
-
- $.ajax({
- url: API_ENDPOINT + "setmenus",
- crossDomain: true,
- contentType: "application/json",
- data: JSON.stringify({
- "choices": toBeSentChoices
- }),
- headers: {
- "Authorization": "Bearer " + currentmeals.token
- },
- dataType: "json",
- cache: false,
- type: "POST",
-
- success: (response) => {
- if (response === null || response.error == true) {
- UIAlert(D("errorSettingMeals"), "setMenus(): response error or null");
- } else if (response.error == false) {
- UIAlert(D("mealSet"), "setMenus(): meni nastavljen");
- } else {
- UIAlert(D("errorUnexpectedResponse"), "setMenus(): invalid response, no condition met");
- }
- setLoading(false);
- },
-
- error: () => {
- setLoading(false);
- UIAlert(D("lopolisAPIConnectionError"), "setMenus(): AJAX error");
- }
- });
-}
-async function setMenu(date, menu) {
- let choice = {};
- choice[date] = menu;
- getToken(getMenus, [setMenus, choice]);
+ let promises_to_run = [
+ localforage.setItem("logged_in_lopolis", true),
+ localforage.setItem("lopolis_username", usernameEl.val()),
+ localforage.setItem("lopolis_password", passwordEl.val())
+ ];
+ await Promise.all(promises_to_run);
+ checkLogin();
+ UIAlert("Credential match!");
+ return true;
}
-
function setupEventListeners() {
$("#meals-login").click(() => {
lopolisLogin();
@@ -310,9 +174,39 @@ function setupEventListeners() {
}
var mealClickHandler = (eventClickInfo) => {
- // console.log("meal clicked!"); // debug
let meal_date = eventClickInfo.event.id;
let meal_object = meals_data_global[meal_date];
+
+ /// ˇˇˇ checkouts
+ $("#checkout_label").show(); let can_do_checkout = true;
+ let checkout_object;
+ try {
+ checkout_object = checkouts_data_global[meal_date];
+ } catch (e) {
+ $("#checkout_label").hide(); let can_do_checkout = false;
+ }
+ if (checkout_object == undefined || checkout_object == null) {
+ can_do_checkout = false;
+ }
+ console.log(checkout_object);
+ if (can_do_checkout) { let cc = $("#checkout_checkbox");
+ cc[0].checked/*in*/ = !(checkout_object.checked/*out*/);
+ cc.off();
+ cc.on("change", ()=>{
+ let l = new lopolisc();
+ checkouts_data_global[meal_date].checked/*out*/ = !(cc[0].checked/*in*/);
+ setLoading(true);
+ l.setCheckouts(checkouts_data_global).then(()=>{ // update server checkots
+ UIAlert(D("successfulCheckingInOut"), "successfulcheckinginout");
+ setLoading(false);
+ }).catch(()=>{
+ UIAlert(D("errorCheckingInOut"), "errorcheckinginout");
+ setLoading(false);
+ });
+ });
+ cc.prop("disabled", checkout_object.readonly);
+ }
+ /// ^^^ checkouts
$("#meal-type").text(meal_object.meal);
let meal_date_obj = new Date(meal_date);
$("#meal-date").text(dateString.longFormatted(meal_date_obj));
@@ -326,12 +220,9 @@ var mealClickHandler = (eventClickInfo) => {
let menu_option_li_el = document.createElement("li");
let menu_option_a_el = document.createElement("button");
menu_option_a_el.innerText = option_object.text;
- // console.log(JSON.stringify(meal_object)); // debug
let classlist = "";
if (option_object.selected != null) {
if(option_object.selected) {
- // console.log("selected"); // debug
- //
classlist = "color: green; font-weight: bold";
}
}
@@ -339,13 +230,25 @@ var mealClickHandler = (eventClickInfo) => {
menu_option_a_el.style = "color: var(--color-text); background-color: rgba(0,0,0,0); line-height: 1.2; height:auto; "+classlist+" !important";
menu_option_a_el.id = "menu_index_"+option_index;
if(!(meal_object.readonly)) {
- menu_option_a_el.onclick = () => {
- setMenu(meal_date, option_object.value);
+ menu_option_a_el.disabled = false;
+ menu_option_a_el.onclick = () => {
+ setLoading(true);
+ let l = new lopolisc();
+ l.chooseMenu(meals_data_global[meal_date], option_index);
+ l.setMeals(meals_data_global).then(()=>{
+ UIAlert(D("mealSet"), "meal set!");
+ setLoading(false);
+ }).catch(()=>{
+ UIAlert(D("errorSettingMeals"), "error setting meals");
+ setLoading(false);
+ });
menu_option_a_el.className = "to-be-selected-meal";
let sidenav_element = document.getElementById("meal-info");
let sidenav_instance = M.Sidenav.getInstance(sidenav_element);
sidenav_instance.close();
};
+ } else {
+ menu_option_a_el.disabled = true;
}
menu_option_li_el.appendChild(menu_option_a_el);
document.getElementById("meal-options").appendChild(menu_option_li_el);
@@ -357,6 +260,7 @@ var mealClickHandler = (eventClickInfo) => {
// Initialization code
document.addEventListener("DOMContentLoaded", async () => {
+ await find_chosen_lang();
checkLogin();
var calendarEl = document.getElementById("meals-calendar");
@@ -377,6 +281,7 @@ document.addEventListener("DOMContentLoaded", async () => {
// Setup refresh handler
$("#refresh-icon").click(function() {
+ setLoading(true);
refreshMeals();
});
@@ -408,5 +313,5 @@ document.addEventListener("DOMContentLoaded", async () => {
format: "dddd, dd. mmmm yyyy"
});
- refreshMeals();
+ // refreshMeals(); // checklogin already does this
});
diff --git a/assets/pages-src/changelog.bvr b/assets/pages-src/changelog.bvr
index 56b883c..e112765 100644
--- a/assets/pages-src/changelog.bvr
+++ b/assets/pages-src/changelog.bvr
@@ -53,6 +53,18 @@
</h3>
<ul class="collapsible">
<li>
+
+ <div class="collapsible-header">Version 1.0.16-beta</div>
+ <div class="collapsible-body">
+ <ul class="collection">
+ <li class="collection-item">Fixed meals</li>
+ <li class="collection-item">Removed LopolisAPI, created
+ lopolisc.js</li>
+ <li class="collection-item">Removed GimB Meet</li>
+ <li class="collection-item">Added checkout option to meals</li>
+ </ul>
+ </div>
+
<div class="collapsible-header">Version 1.0.15-beta</div>
<div class="collapsible-body">
<ul class="collection">
@@ -60,7 +72,6 @@
</ul>
</div>
-
<div class="collapsible-header">Version 1.0.14-beta</div>
<div class="collapsible-body">
<ul class="collection">
diff --git a/assets/pages-src/meals.bvr b/assets/pages-src/meals.bvr
index c0d655b..2fd4840 100644
--- a/assets/pages-src/meals.bvr
+++ b/assets/pages-src/meals.bvr
@@ -17,20 +17,18 @@
<script src="/js/lib/jquery.min.js"></script>
<!-- localForage -->
<script type="text/javascript" src="/js/lib/localforage.min.js"></script>
+ <!-- i18n bundle -->
+ <script src="/js/lang/bundle.js"></script>
<!-- mergedeep.js -->
<script type="text/javascript" src="/js/lib/mergedeep.js"></script>
<!-- stylesheet for custom styles -->
<link type="text/css" href="/css/styles.css" rel="stylesheet">
- <!-- page-specific javascript code -->
- <script type="text/javascript" src="/js/meals.js"></script>
<!-- PWA manifest -->
<link rel="manifest" href="/manifest.json">
<!-- app global code -->
<script src="/js/app.js"></script>
<!-- code for custom theme switcher -->
<script src="/js/lib/themes.js"></script>
- <!-- i18n bundle -->
- <script src="/js/lang/bundle.js"></script>
<!-- favicon -->
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
<!-- iOS support -->
@@ -43,6 +41,10 @@
<link href="/css/fullcalendar/custom.css" rel="stylesheet" />
<script src="/js/lib/fullcalendar/core/main.min.js"></script>
<script src="/js/lib/fullcalendar/daygrid/main.min.js"></script>
+ <!-- lopolis client API library - unofficial by sijanec -->
+ <script src="/js/lopolisc.js"></script>
+ <!-- page-specific javascript code -->
+ <script type="text/javascript" src="/js/meals.js"></script>
</head>
<body>
@@ -81,6 +83,16 @@
<x-du>readOnly</x-du>
</a>
</li>
+ <li>
+ <div class=switch style=margin-left:0.7cm>
+ <label id=checkbox_label style>
+ <x-su>checkedOut</x-su>
+ <input id=checkout_checkbox type=checkbox>
+ <span class=lever></span>
+ <x-su>checkedIn</x-su>
+ </label>
+ </div>
+ </li>
<div class=divider></div>
<li id=meal-options>
diff --git a/assets/pages-src/misc/grading-add-modal.bvr b/assets/pages-src/misc/grading-add-modal.bvr
index 0b7189d..6017189 100644
--- a/assets/pages-src/misc/grading-add-modal.bvr
+++ b/assets/pages-src/misc/grading-add-modal.bvr
@@ -1,3 +1,4 @@
+<!-- @begin=html@ -->
<!-- Modal Structure -->
<div id="beziapp-add-grading" class="modal modal-fixed-footer">
diff --git a/assets/pages-src/misc/matomo.bvr b/assets/pages-src/misc/matomo.bvr
index d57beb0..614e210 100644
--- a/assets/pages-src/misc/matomo.bvr
+++ b/assets/pages-src/misc/matomo.bvr
@@ -28,42 +28,32 @@ let promises_to_run_app = [
Promise.all(promises_to_run_app).then(() => {
-if (BEZIAPP_USERNAME == null || BEZIAPP_USERNAME == "") {
- var username_report = "neprijavljen.uporabnik";
-} else {
- var username_report = BEZIAPP_USERNAME;
-}
-if (BEZIAPP_LOPOLIS_USERNAME == null || BEZIAPP_LOPOLIS_USERNAME == "") {
- var lopolis_username_report = "NEPRIJAVLJENUPORABNIK";
-} else {
- var lopolis_username_report = BEZIAPP_LOPOLIS_USERNAME;
-}
-if (BEZIAPP_LANGUAGE == null || BEZIAPP_LANGUAGE == "") {
- var language_report = "unspecified_language";
-} else {
- var language_report = BEZIAPP_LANGUAGE
-}
-if (BEZIAPP_THEME == null || BEZIAPP_THEME == "") {
- var theme_report = "unspecified_theme";
-} else {
- var theme_report = BEZIAPP_THEME;
-}
-if (BEZIAPP_ERRORREPORTING == null || BEZIAPP_ERRORREPORTING == "") {
- var errorreporting_report = "unspecified-errorreporting";
-} else {
- var errorreporting_report = BEZIAPP_ERRORREPORTING;
-}
-
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setDoNotTrack", true]);
- _paq.push(['setUserId', username_report]);
+
+ if (BEZIAPP_USERNAME == null || BEZIAPP_USERNAME == "") {
+ } else {
+ _paq.push(['setUserId', BEZIAPP_USERNAME]);
+ }
+ if (BEZIAPP_LOPOLIS_USERNAME == null || BEZIAPP_LOPOLIS_USERNAME == "") {
+ } else {
+ _paq.push(['setCustomVariable', 1, 'lopolis-username', BEZIAPP_LOPOLIS_USERNAME, 'visit']);
+ }
+ if (BEZIAPP_LANGUAGE == null || BEZIAPP_LANGUAGE == "") {
+ } else {
+ _paq.push(['setCustomVariable', 2, 'language', BEZIAPP_LANGUAGE, 'visit']);
+ }
+ if (BEZIAPP_THEME == null || BEZIAPP_THEME == "") {
+ } else {
+ _paq.push(['setCustomVariable', 3, 'theme', BEZIAPP_THEME, 'visit']);
+ }
+ if (BEZIAPP_ERRORREPORTING == null || BEZIAPP_ERRORREPORTING == "") {
+ } else {
+ _paq.push(['setCustomVariable', 4, 'errorreporting', BEZIAPP_ERRORREPORTING, 'visit']);
+ }
_paq.push(['enableHeartBeatTimer', 30]);
- _paq.push(['setCustomVariable', 1, 'lopolis-username', lopolis_username_report, 'visit']);
- _paq.push(['setCustomVariable', 2, 'language', language_report, 'visit']);
- _paq.push(['setCustomVariable', 3, 'theme', theme_report, 'visit']);
- _paq.push(['setCustomVariable', 4, 'errorreporting', errorreporting_report, 'visit']);
_paq.push(['setCustomVariable', 5, 'domain', window.location.host, 'visit']);
_paq.push(['trackPageView']);
_paq.push(['trackAllContentImpressions']);
diff --git a/assets/pages-src/misc/msg-compose-modal.bvr b/assets/pages-src/misc/msg-compose-modal.bvr
index 48afaaf..ac91b83 100644
--- a/assets/pages-src/misc/msg-compose-modal.bvr
+++ b/assets/pages-src/misc/msg-compose-modal.bvr
@@ -1,3 +1,4 @@
+<!-- @begin=html@ -->
<!-- Modal Structure -->
<div id="beziapp-new-message" class="modal modal-fixed-footer">
diff --git a/assets/pages-src/misc/navigation.bvr b/assets/pages-src/misc/navigation.bvr
index 2f0da71..3b5b1a5 100644
--- a/assets/pages-src/misc/navigation.bvr
+++ b/assets/pages-src/misc/navigation.bvr
@@ -1,3 +1,4 @@
+<!-- @begin=html@ -->
<ul id="side-menu" class="sidenav side-menu">
<li><a class="subheader"><h4 class="sidenav-beziapp-subheader"><b>Beži</b>App</h4></a></li>
<li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i><x-su>timetable</x-su></a></li>
@@ -8,7 +9,8 @@
<li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i><x-su>messaging</x-su></a></li>
<!-- chats not done yet, expecting merge so removing from navigation panel --sijanec -->
<!-- <li><a href="/pages/chats.html" class="waves-effect"><i class="material-icons">chat</i><x-su>chat</x-su></a></li> -->
- <li><a href="/pages/jitsi.html" class="waves-effect"><i class="material-icons">video_call</i><x-su>videoconferences</x-su></a></li>
+ <!-- <li><a href="/pages/jitsi.html" class="waves-effect"><i class="material-icons">video_call</i><x-su>videoconferences</x-su></a></li> -->
+ <!-- jitsi got reverted to jitsi from gimb meet so it's sucky to show this -->
<li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i><x-su>meals</x-su></a></li>
<li><div class="divider"></div></li>
<li><a href="/pages/about.html" class="waves-effect"><i class="material-icons">info</i><x-su>about</x-su></a></li>
diff --git a/assets/root/sw.js.bvr b/assets/root/sw.js.bvr
index 45ac9dd..5f0979f 100644
--- a/assets/root/sw.js.bvr
+++ b/assets/root/sw.js.bvr
@@ -1,4 +1,5 @@
<@?i global@>
+// @begin=js@
// Change version to cause cache refresh
const static_cache_name = "site-static-<@?g app_version@>-<@?u 0 7 ?g latest_commit@>";
// commit before the latest is <@?g latest_commit@>