summaryrefslogblamecommitdiffstats
path: root/assets/js/gsec.js
blob: 73e8fd220aa1045e3ba0acbc580d0eb9cd617e97 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                  
                                                                         
                                                                                                   
 
                                               
                                                       
 
 
                          



                                                 
 
                                         


                                                                                    
 
 
                                               


                                                                                     


                                

                                          
                                                               

                                                    
 
            
 

















































































































































































































































                                                                                                                                                                   






                                                                                                 

                                                                                           




































































































































































































                                                                                                                                                                                           

                                                                                                                                                                          





                                                                                                                                                          
                                                         






                                                                                                                               





                                                                                                                                                                                  






















                                                                                                                                                 
                                                 






















                                                                                          
                                                                                                                                   

















































































                                                                                                                                                                                  
                                                                                
                                                                                                                        
                                         

























































                                                                                                                                           
 
// tab = 2 || any spaces; use tabs
// not tested yet -- NOTE: document.createElement is xssy, use DOMParser!
var gseAbsenceTypes = ["notProcessed", "authorizedAbsence", "unauthorizedAbsence", "doesNotCount"];

function getStringBetween(string, start, end) {
	return string.split(start).pop().split(end)[0];
}

function stripHtml(html) {
   var tmp = document.createElement("DIV");
   tmp.innerHTML = html;
   return tmp.textContent || tmp.innerText || "";
}

function slDayToInt(inputString) { // wtf
	let fourChars = inputString.substring(1, 5);
	let fourCharDays = ["oned", "orek", "reda", "etrt", "etek", "obot", "edel"];
	return fourCharDays.indexOf(fourChars);
}

const GSE_URL = "https://zgimsis.gimb.tk/gse/";
const GSEC_ERR_NET = "GSEC NETWORK ERROR (ajax error)";
const GSEC_ERR_NET_POSTBACK_GET = "GSEC NETWORK ERROR (ajax error) in postback GET"
const GSEC_ERR_NET_POSTBACK_POST = "GSEC NETWORK ERROR (ajax error) in postback POST"
const GSEC_MSGTYPE_RECEIVED = 0;
const GSEC_MSGTYPE_SENT = 1;
const GSEC_MSGTYPE_DELETED = 2;
const GSEC_ERR_LOGIN = "GSEC LOGIN ERROR";
const GSEC_NO_ABSENCES = "noAbsences";
const GSEC_MSGTYPES = ["msgReceived", "msgSent", "msgDeleted"];
const GSEC_NORMAL_GRADE = "GSEC NORMAL GRADE";
const GSEC_ZAKLJUCNA_GRADE = "GSEC ZAKLJUCNA GRADE";

class gsec {

	constructor() {
	}

	parseAndPost(inputHTML, params, 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 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
				}
			}
		
			var action;
			if (useDiffAction == null || useDiffAction == false) {
				action = new URL($(form).attr("action"), GSE_URL); // absolute == relative + base
			} else {
				action = useDiffAction;
			}

			$.ajax({
				xhrFields: {
					withCredentials: true
				},
				crossDomain: true,
				url: action,
				cache: false,
				type: "POST",
				data: params,
				dataType: "text",
				success: (postData, textStatus, xhr) => {
					resolve({data: postData, textStatus: textStatus, code: xhr.status});
				},
				error: () => {
					reject(new Error(GSEC_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);
					});
				},
				error: () => {
					reject(new Error(GSEC_ERR_NET_POSTBACK_GET));
				}
			});
		});
	}

	login(usernameToLogin, passwordToLogin) {
		return new Promise((resolve, reject) => {
			var dataToSend = {
				"edtGSEUserId": usernameToLogin,
				"edtGSEUserPassword": passwordToLogin,
				"btnLogin": "Prijava"
			};
			this.postback(GSE_URL + "Logon.aspx", dataToSend, null, true).then((response) => {
				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");
				if (response.code === 302) {
					resolve(true);
				} else {
					if (parsed.getElementById("lblMsg")) { // če obstaja lblMsg (napaka pri prijavi)
						reject(new Error(GSEC_ERR_LOGIN));
					} else if (!(parsed.getElementById("ctl00_lblLoginName"))) { // če ni ctl00_lblLoginName nismo na Default.aspx
						reject(new Error(GSEC_ERR_LOGIN));
					} else {
						resolve(parsed.getElementById("ctl00_lblLoginName").innerHTML); // vrne ime dijaka, to je lahko uporabno
					}
				}
			});
		});
	}

	fetchSessionData() {
		return new Promise((resolve, reject) => {
			$.ajax({
				xhrFields: {
					withCredentials: true
				},
				crossDomain: true,
				url: GSE_URL + "WS_Gim/wsGimSisUtils.asmx/GetSessionData",
				type: "POST",
				dataType: "json",
				cache: false,
				contentType: "application/json",
				data: "{}",
				processData: false,
				success: (data, textStatus, xhr) => {
					var podatki = {};
					podatki[0] = data.d.split(", ")[0];
					podatki[1] = data.d.split(", ")[1];
					podatki["username"] = data.d.split(", ")[1];
					podatki[2] = data.d.split(", ")[2];
					podatki[3] = data.d.split(", ")[3];
					podatki["sessionCookie"] = data.d.split(", ")[3];
					podatki[4] = data.d.split(", ")[4];
					resolve({"data": podatki, "textStatus": textStatus, "code": xhr.status});
				},
				error: () => {
					reject(new Error(false));
				}
			});
		});
	}

	fetchTeachersDirectory() {
		return new Promise((resolve, reject) => {
			var currentDate = new Date();
			// če je že po avgustu (september), uporabimo trenutno letnico
			// če še ni avgust uporabimo preteklo leto/letnico
			// skratka uporabi se prvi sklop številk v šolskem letu TOLE(XXXX/yyyy)
			var letnica = currentDate.getFullYear();
			if (currentDate.getMonth() < 7) {
				letnica--;
			}

			$.ajax({
				xhrFields: {
					withCredentials: true
				},
				crossDomain: true,
				url: GSE_URL + "Page_Gim/Uporabnik/modSporociloPrejemniki.aspx/NajdiOsebePrejemniki",
				type: "POST",
				dataType: "json",
				contentType: "application/json",
				cache: false,
				data: JSON.stringify({
					"aIdOsebeRe": "",
					"aIdSolskoLeto": Number(letnica).toString(),
					"aMsgType": "null",
					"aIdType": "null",
					"aIdUcitelj": "",
					"aFilter": null
				}),
				// note about the nulls, "null"s and ""s: this is actually how zgimsisext2016 javascripts sends it.
				processData: false,
				success: (data) => {
					var teachersDirectory = data.d.split(";"); // data.d je "12434=Ime Primek (učitelj);75353=Ime Drugega Priimek (učitelj)";
					teachersDirectory.pop(); // pop, ker se string konča z ;
					var formatted = {};
					teachersDirectory.forEach((v) => {
						formatted[v.split("=")[1].split(" (")[0]] = v.split("=")[0];
					});
					resolve(formatted);
				},
				error: () => {
					reject(new Error(false));
				}
			});
		});
	}

	fetchTimetable(datum = null) {

		const SUBJECT_REGEX = /\((.+?)\)/;
		const ABKURZUNG_REGEX = /^(.+?) \(/;

		var dataToSend = datum == null ? {} : {
			"ctl00$ContentPlaceHolder1$wkgDnevnik_edtGridSelectDate": `${datum.getDate()}.${Number(datum.getMonth()+1)}.${datum.getFullYear()}`
		};

		return new Promise((resolve) => {
			var urnik = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6:{} } ;
			this.postback(GSE_URL+"Page_Gim/Ucenec/DnevnikUcenec.aspx", dataToSend, null, true).then((response) => {
				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");
				for (const urnikElement of parsed.querySelectorAll('*[id^="ctl00_ContentPlaceHolder1_wkgDnevnik_btnCell_"]')) {
					var subFields = urnikElement.id.split("_");
					var period = subFields[4];
					var day = subFields[5];
					var desc = $(urnikElement).attr("title").split("\n");
					var subject = SUBJECT_REGEX.exec(desc[1])[1];
					var abkurzung = ABKURZUNG_REGEX.exec(desc[1])[1];
					var razred = desc[2];
					var teacher = desc[3];
					var place = desc[4];
					urnik[day][period] = {
						"subject": subject,
						"acronym": abkurzung,
						"class": razred,
						"teacher": teacher,
						"place": place
					};
				}
				resolve(urnik);
			});
		});
	}

	fetchGradings() {

		const DESC_REGEX = /\((.+?)\)/m;
		const SUBJECT_REGEX = /^(.+?) \(/m;

		return new Promise((resolve) => {
			var gradings = [];
			this.postback(GSE_URL + "Page_Gim/Ucenec/IzpitiUcenec.aspx", {}, null, true).then( (response) => {

				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");

				var rowElements = parsed.getElementsByTagName("table")[0].getElementsByTagName("tbody")[0].getElementsByTagName("tr");

				for (const row of rowElements) {
					var subFields = row.getElementsByTagName("td");
					var date = subFields[0].innerHTML.trim().split(".");
					var dateObj = new Date(date[2]+"-"+date[1]+"-"+date[0]);
					var rowSpan = subFields[1].getElementsByTagName("span")[0];
					var abkurzung = "";

					if (rowSpan) {
						abkurzung = rowSpan.innerHTML.trim();
					}

					rowSpan.remove(); // magic
					
					var subject = SUBJECT_REGEX.exec(subFields[1].innerHTML);
					if (subject == null) {
						continue;
					}
					subject = subject[1].trim();

					var desc = DESC_REGEX.exec(subFields[1].innerHTML);
					desc = desc == null ? "" : desc[1];

					gradings.push({
						"date": dateObj,
						"acronym": abkurzung,
						"subject": subject,
						"description": desc
					});
				}
				resolve(gradings);
			});
		});
	}

	fetchTeachers() { // razrednika ne vrne kot razrednika, če le-ta uči še en predmet. razlog: razrednik je napisan dvakrat, drugič se prepiše. Ne da se mi popravljat.

		const SUBJECT_REGEX = /^(.+?(?= \()|.+(?! \())/; // For some reason, JS doesn't support conditional regex
		const ABKURZUNG_REGEX = /\((.+)\)/;
		const DAY_REGEX = /^(.+?), /m;
		const PERIOD_REGEX = /, (\d+?)\. ura/;
		const TIME_RANGE_REGEX = /\((.+?) - (.+?)\)/;

		return new Promise((resolve) => {
			var Teachers = {};

			this.postback(GSE_URL + "Page_Gim/Ucenec/UciteljskiZbor.aspx", {}, null, true).then((response) => {

				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");

				var rowElements = parsed.getElementsByTagName("table")[0].getElementsByTagName("tbody")[0].getElementsByTagName("tr");

				for (const row of rowElements) {
					var subFields = row.getElementsByTagName("td");
					var name = stripHtml(subFields[0].innerHTML); // razrednik je namreč bold tekst!
					var subjectStrings = subFields[2].innerHTML.split("<br>");
					var subjects = {};

					for (const subjectString of subjectStrings) {
						var subjectName = SUBJECT_REGEX.exec(stripHtml(subjectString))[1];
						var abkurzung = ABKURZUNG_REGEX.exec(stripHtml(subjectString));
						abkurzung = abkurzung == null ? subjectName : abkurzung[1];
						subjects[abkurzung] = subjectName;
					}

					try {
						var TP = {};
						TP.day = slDayToInt(DAY_REGEX.exec(subFields[3].innerHTML)[1]);
						TP.period = Number(PERIOD_REGEX.exec(subFields[3].innerHTML)[1]);
						var time_range_matches = TIME_RANGE_REGEX.exec(subFields[3].innerHTML);
						TP.from = time_range_matches[1];
						TP.till = time_range_matches[2];
						if (TP.day < 0) { // indexOf vrne -1, če v arrayu ne najde dneva (&nbsp;)
							TP = false;
						}
					} catch (error) {
						var TP = {};
						TP.day = slDayToInt(subFields[3].innerHTML.split(", ")[0]);
						TP.period = Number( subFields[3].innerHTML.split(", ").pop().split(". ura")[0] );
						TP.from = subFields[3].innerHTML.split("(").pop().split(")")[0].split(" - ")[0];
						TP.till = subFields[3].innerHTML.split("(").pop().split(")")[0].split(" - ")[1];
						if (TP.day < 0) { // indexOf vrne -1, če v arrayu ne najde dneva (&nbsp;)
							TP = false;
						}
					}

					Teachers[name] = { "subjects" : subjects , "tpMeetings" : TP };
				}
				resolve(Teachers);
			});
		});
	}

	sendMessage(recipient, subject = " ", body = " ") {
		return new Promise((resolve) => {
			var dataToSend = {
				"ctl00$ModalMasterBody$edtPrejemniki": "",
				"ctl00$ModalMasterBody$edtZadeva": subject,
				"ctl00$ModalMasterBody$edtBesediloExt": he.encode(body, {useNamedReferences: true}),
				"__EVENTTARGET": "ctl00$ModalMasterBody$btnDogodekShrani",
				"__EVENTARGUMENT": "",
				"ctl00$ModalMasterBody$hfPrejemniki": recipient
			};
			this.postback(GSE_URL+"Page_Gim/Uporabnik/modSporocilo.aspx?params=", dataToSend, null, true).then(() => {
				resolve(null);
			});
		});
	}

	deleteMessage(id) {
		return new Promise((resolve, reject) => {
			$.ajax({
				xhrFields: {
					withCredentials: true
				},
				crossDomain: true,
				url: GSE_URL + "Page_Gim/Uporabnik/Sporocila.aspx/DeleteMessage",
				type: "POST",
				dataType: "json",
				cache: false,
				contentType: "application/json",
				data: JSON.stringify({
					"aIdSporocilo": id.split("|")[0],
					"aIdZapis": id.split("|")[1]
				}),
				processData: false,
				success: (data) => {
					if(data.d == true) {
						resolve(true);
					} else {
						reject(new Error(false));
					}
				},
				error: () => {
				reject(new Error(GSEC_ERR_NET));
				}
			});
		});
	}

	fetchAbsences(fromDate = null, tillDate = null) { // navedba datumov je deprecated. Internet je dovolj hiter za poslat maksimalno 4160 ur (16 ur/dan, 5 dni/ted, 52 ted/leto)

		const SUBJECT_LIST_REGEX = /(.+? \(<span class="opr\d">\dP?<\/span>\))(?:,\s*|$)/g;
		const FIELDS_REGEX = /^(.+?) \(<span class="opr(\d)">(\dP?)<\/span>\)/;

		return new Promise((resolve) => {
			if (!(fromDate instanceof Date) || !(tillDate instanceof Date)) {
				tillDate = new Date(Date.UTC(9999, 11, 30)); // overkill? Of course not, cez 8000 let bo ta app se vedno top shit
				fromDate = new Date(Date.UTC(1, 1, 1)); // i don't think so
			}

			var dataToBeSent = {
				"ctl00$ContentPlaceHolder1$edtDatZacetka": `${fromDate.getDay()}.${fromDate.getMonth()}.${fromDate.getFullYear()}`,
				"ctl00$ContentPlaceHolder1$edtDatKonca": `${tillDate.getDay()}.${tillDate.getMonth()}.${tillDate.getFullYear()}`,
			};

			this.postback(GSE_URL+"Page_Gim/Ucenec/IzostankiUcenec.aspx", dataToBeSent, null, true).then((response) => {
				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");

				try {
					var rowElements = parsed.getElementById("ctl00_ContentPlaceHolder1_gvwIzostankiGroup").getElementsByTagName("tbody")[0].getElementsByTagName("tr");
				} catch (err) {
					resolve(GSEC_NO_ABSENCES);
				}

				var absences = [];
				 for (const izostanek of rowElements) {
					var subFields = izostanek.getElementsByTagName("td");
					var date = subFields[0].innerHTML.trim().split(".");
					var dateObj = new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));

					var subjects = [];
					subFields[2].innerHTML.match(SUBJECT_LIST_REGEX).forEach((subject) => {
						subjects.push(subject);
					});

					var absencesBySubject = {};

					for (const subject of subjects) {
						const matched_info = FIELDS_REGEX.exec(subject);

						var subjectName = matched_info[1];
						var status = Number(matched_info[2]);
						// statusi so: 0: ni obdelano, 1: opravičeno, 2: neopravičeno, 3: ne šteje, uporabi S(gseAbsenceTypes[num]) za i18n prevod
						// Ce je v "stevilki" P, gre za popoldansko uro -> +7 ur
						var period = matched_info[3];
						period = period.includes("P") ? Number(period.replace("P", "")) + 7 : Number(period);
						absencesBySubject[period] = {status: status, subject: subjectName};
					}
					absences.push({subjects: absencesBySubject, date: dateObj});
				}
				resolve(absences);
			});
		});
	}

	fetchGrades() {
		var grades = [];
		return new Promise((resolve, reject) => {
			$.ajax({
				xhrFields: {
					withCredentials: true
				},
				crossDomain: true,
				url: GSE_URL + "Page_Gim/Ucenec/OceneUcenec.aspx",
				cache: false,
				type: "GET",
				dataType: "html",
				processData: false,

				success: (data) => {

					let parser = new DOMParser();
					let parsed = parser.parseFromString(data, "text/html");

					let gradeSpans = parsed.getElementsByClassName("txtVOcObd");
					for (const grade of gradeSpans) {
						var whatever_ist_meant_in_my_head_back_then_but_as_a_string = grade.getElementsByTagName("span")[0].getAttribute("title");
						var ist = whatever_ist_meant_in_my_head_back_then_but_as_a_string.split("\n");
						if (ist.length == 1) { // that means the txtVOcObd defines a zaključno oceno // gimsis is just utter crap
							var gradeToAdd = {
								"gradeType": GSEC_ZAKLJUCNA_GRADE,
								"grade": Number(grade.getElementsByTagName("span")[0].innerHTML),
								"subject": grade.parentElement.parentElement.parentElement.parentElement.
									getElementsByTagName("th")[0].innerText // I fucking hope this works
							}
							grades.push(gradeToAdd);
						} else {
							var date = ist[0].split(": ")[1].trim().split(".");
							var dateObj = new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));
							var teacher = ist[1].split(": ")[1].trim();
							var subject = ist[2].split(": ")[1].trim();
							var name = [];
							
							name.push(whatever_ist_meant_in_my_head_back_then_but_as_a_string.split("Ocenjevanje: ")[1].split("\nVrsta: ")[0].trim());
							name.push(whatever_ist_meant_in_my_head_back_then_but_as_a_string.split("Vrsta: ")[1].split("\nRok: ")[0].trim())
							name.push(whatever_ist_meant_in_my_head_back_then_but_as_a_string.split("Rok: ")[1].trim())
							// prov predstavljam si enga profesorja, ke bo v polje Ocenjevanje vnesel "Vrsta: " in spet BREAKAL
							// FKING algoritem.
							var gradeNumber = Number(grade.getElementsByTagName("span")[0].innerHTML);
							var temporary = grade.getElementsByTagName("span")[0].classList.contains("ocVmesna");

							var gradeToAdd = {
								"gradeType": GSEC_NORMAL_GRADE, // well said I must say
								"date": dateObj,
								"teacher": teacher,
								"subject": subject,
								"name": name,
								"temporary": temporary,
								"grade": gradeNumber
							};

							if (grade.getElementsByTagName("span").length > 1) {
								if(grade.getElementsByTagName("span")[1].classList.contains("ocVmesna")) {
									gradeToAdd["temporary"] = true;
								} else {
									gradeToAdd["temporary"] = false;
								}
								gradeToAdd["grade"] = Number(grade.getElementsByTagName("span")[1].innerHTML);
								gradeToAdd["oldgrade"] = Number(grade.getElementsByTagName("span")[0].innerHTML);
							}
							grades.push(gradeToAdd);
						}
					}
					resolve(grades);
				},
				error: () => {
					reject(new Error(GSEC_ERR_NET));
				}
			});
		});
	}

	fetchMessageOld(selectId) { // ne dela, glej fix spodaj (fetchMessage)

		const TIME_REGEX = / \(.+ (.+?)\)/;
		const DATE_REGEX = / \(.+? /;
		const SENDER_REGEX = /^(.+?) \(/;

		var message;
		return new Promise((resolve) => {
			var dataToBeSent = {
				"__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila",
				"__EVENTARGUMENT": "Select$" + selectId
			};

			this.postback(GSE_URL + "Page_Gim/Uporabnik/Sporocila.aspx", dataToBeSent, null, true).then((response) => {
				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");
				let subject = parsed.getElementsByClassName("msgSubjectS")[0].innerHTML.trim();
				let body = parsed.getElementsByClassName("gCursorAuto")[0].innerHTML.trim();
				let sender = SENDER_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1];
				let recipient = parsed.querySelectorAll("[id$=Label8]")[0].innerHTML;
				var date = DATE_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1];
				var tume = TIME_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1]; // "tume"!
				var dateObj = new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]} ${tume}`)); // "tume"!
				var msgId = parsed.getElementById("ctl00_ContentPlaceHolder1_hfIdSporocilo").getAttribute("value");
				message = {
					"subject": subject,
					"body": body,
					"sender": sender,
					"recipient": recipient,
					"date": dateObj,
					"msgId": msgId
				};
				resolve(message);
			});
		});
	}

	fetchMessagesLastPageNumber(category = GSEC_MSGTYPE_RECEIVED) {
		var msgCategory = GSEC_MSGTYPES[category];
		return new Promise((resolve) => {
			var dataToBeSent = {
				"ctl00$ContentPlaceHolder1$ddlPrikaz": msgCategory,
				"__EVENTARGUMENT": "Page$Last",
				"__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila"
			};
			this.postback(GSE_URL+"Page_Gim/Uporabnik/Sporocila.aspx", dataToBeSent, null, true).then((response) => {
				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");
				let currentPage;
				if (parsed.getElementsByClassName("pager").length == 0) { // pager is not shown, there is only page one.
					currentPage = 1;
				} else {
					currentPage = Number(parsed.getElementsByClassName("pager")[0].getElementsByTagName("span")[0].innerHTML);
				}
				resolve(currentPage);
			});
		});
	}

	fetchMessagesList(category = GSEC_MSGTYPE_RECEIVED, pageNumber = 1, outputResponse = false) { // outputResponse je probably za debug

		const DATE_REGEX = /(\d+?).(\d+?).(\d+?) /; // I'm lazy

		var msgCategory = GSEC_MSGTYPES[category];
		var messages = [];
		var requestURI = GSE_URL + "Page_Gim/Uporabnik/Sporocila.aspx";
		return new Promise((resolve) => {
			var dataToBeSent = {
				"ctl00$ContentPlaceHolder1$ddlPrikaz": msgCategory,
				"__EVENTARGUMENT": "Page$" + pageNumber,
				"__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila"
			};
			this.postback(requestURI, dataToBeSent, null, true).then((response) => {
				if (outputResponse === true) {
					response.url = requestURI;
					resolve(response);
				}

				let parser = new DOMParser();
				let parsed = parser.parseFromString(response.data, "text/html");
				let messageElements = parsed.getElementById("ctl00_ContentPlaceHolder1_gvwSporocila").getElementsByTagName("tbody")[0].getElementsByTagName("td");
				for (const messageElement of messageElements) {
					let msgId = messageElement.getElementsByTagName("input")[0].value;
					var date = DATE_REGEX.exec(messageElement.getElementsByClassName("msgSubDate")[0].innerHTML);
					var today = new Date();

					if (date[3] == undefined || date[2].length < 1) {
						date[3] = today.getFullYear();
					}

					if (date[2] == undefined || date[2].length < 1) {
						date[2] = today.getMonth() + 1;
						date[1] = today.getDate();
					}

					var tume = messageElement.getElementsByClassName("msgSubDate")[0].innerHTML.split(" ")[1];
					if (tume == null || tume.length === 0) {
						tume = messageElement.getElementsByClassName("msgSubDate")[0].innerHTML;
					}
					var dateStringToParse = `${date[2]}-${date[1]}-${date[0]} ${tume}`;
					var dateObj = new Date(Date.parse(dateStringToParse)); // "tume"!
					var person = messageElement.getElementsByClassName("msgDir")[0].innerHTML;
					var subject = messageElement.getElementsByClassName("msgSubject")[0].innerHTML;
					messages.push({
						"date": dateObj,
						"sender": person,
						"subject": subject,
						"msgId": msgId
					});
				}
				resolve(messages);
			});
		});
	}

	fetchMessage(category = GSEC_MSGTYPE_RECEIVED, pageNumber = 1, messageNumberOnPage = 0) {

		const TIME_REGEX = / \(.+ (.+?)\)/;
		const DATE_REGEX = / \((\d+?).(\d+?).(\d+?) /;
		const SENDER_REGEX = /^(.+?) \(/;
			
		return new Promise((resolve) => {
			this.fetchMessagesList(category, pageNumber, true).then( (value) => {
				this.parseAndPost(
					value.data,
					{
						"__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila",
						"__EVENTARGUMENT": "Select$" + messageNumberOnPage
					},
					null,
					value.url
				).then((response) => {

					let parser = new DOMParser();
					let parsed = parser.parseFromString(response.data, "text/html");
					let subject = parsed.getElementsByClassName("msgSubjectS")[0].innerHTML.trim();
					let body = parsed.getElementsByClassName("gCursorAuto")[0].innerHTML.trim();
					let sender = SENDER_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1];
					let recipient = parsed.querySelectorAll("[id$=Label8]")[0].innerHTML;
					var date = DATE_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML);
					var tume = TIME_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1]; // "tume"!
					var dateObj = new Date(Date.parse(`${date[3]}-${date[2]}-${date[1]} ${tume}`)); // "tume"!
					var msgId = parsed.getElementById("ctl00_ContentPlaceHolder1_hfIdSporocilo").getAttribute("value");
					var message = {
						"subject": subject,
						"body": body,
						"sender": sender,
						"recipient": recipient,
						"date": dateObj,
						"msgId": msgId
					};
					resolve(message);

				});
			});
		});
	}
}