diff --git a/entity/Appointment_entity/Appointment_entity.aod b/entity/Appointment_entity/Appointment_entity.aod index d615ac8db071653c41b13edc8e574505ab3f4b50..ebfd0f83c692dbda16668ec3f20a2da687b74c0e 100644 --- a/entity/Appointment_entity/Appointment_entity.aod +++ b/entity/Appointment_entity/Appointment_entity.aod @@ -270,6 +270,7 @@ <jDitoRecordAlias>Data_alias</jDitoRecordAlias> <contentProcess>%aditoprj%/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js</contentProcess> <rowCountProcess>%aditoprj%/entity/Appointment_entity/recordcontainers/jdito/rowCountProcess.js</rowCountProcess> + <hasDependentRecords v="true" /> <onInsert>%aditoprj%/entity/Appointment_entity/recordcontainers/jdito/onInsert.js</onInsert> <onUpdate>%aditoprj%/entity/Appointment_entity/recordcontainers/jdito/onUpdate.js</onUpdate> <onDelete>%aditoprj%/entity/Appointment_entity/recordcontainers/jdito/onDelete.js</onDelete> diff --git a/entity/Appointment_entity/afterUiInit.js b/entity/Appointment_entity/afterUiInit.js index 84f0515ebf4c6c9ba00bb4a071bacebe74fbaace..d1a3fedb127f027d614ce245fc9901599743d2a3 100644 --- a/entity/Appointment_entity/afterUiInit.js +++ b/entity/Appointment_entity/afterUiInit.js @@ -2,7 +2,7 @@ import("system.util"); import("system.neon"); import("system.vars"); -if(vars.exists("$param.Entry_param") && vars.get("$param.Entry_param")) +if(vars.get("$param.Entry_param")) { var entry = JSON.parse(vars.getString("$param.Entry_param")); diff --git a/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js b/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js index 709bfac8d00e3b805a383dc0c78c0cb8b91a07d1..a2b8753c1cf9bcd5783b27f12226693770d0e7af 100644 --- a/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/Appointment_entity/recordcontainers/jdito/contentProcess.js @@ -18,12 +18,12 @@ var appointmentUids; /** * Will be used, if the user is operating the calendar. */ -if(vars.exists("$param.Entry_param") && vars.get("$param.Entry_param")) +if(vars.get("$param.Entry_param") && JSON.parse(vars.get("$param.Entry_param"))[calendars.ID] != undefined) { var entry = JSON.parse(vars.getString("$param.Entry_param")); var masterEntry = null; - if (vars.exists("$param.MasterEntry_param") && vars.get("$param.MasterEntry_param") != "") { + if (vars.get("$param.MasterEntry_param") != "") { masterEntry = JSON.parse(vars.getString("$param.MasterEntry_param")); } diff --git a/entity/Appointment_entity/recordcontainers/jdito/onInsert.js b/entity/Appointment_entity/recordcontainers/jdito/onInsert.js index 21d79d0f9f82bfa904e33604db62defa2ca9733f..548745a3cf60a6dfa340e0dec3315f2345f18534 100644 --- a/entity/Appointment_entity/recordcontainers/jdito/onInsert.js +++ b/entity/Appointment_entity/recordcontainers/jdito/onInsert.js @@ -8,6 +8,7 @@ import("system.neon"); import("system.vars"); import("system.text"); import("system.db"); +import("system.entities"); var event = JSON.parse(vars.getString("$param.Entry_param")); @@ -22,36 +23,23 @@ event[calendars.LOCATION] = fields["LOCATION.value"]; event[calendars.DESCRIPTION] = fields["DESCRIPTION.value"]; event[calendars.DTSTART] = fields["BEGIN.value"]; event[calendars.DTEND] = fields["END.value"]; -event["X-ADITO-ISALLDAYEVENT"] = fields["ALLDAY.value"]; event[calendars.CLASSIFICATION] = fields["CLASSIFICATION.value"]; event[calendars.TRANSPARENCY] = fields["TRANSPARENCY.value"]; event[calendars.CATEGORIES] = fields["CATEGORIES.value"]; event[calendars.ORGANIZER] = fields["ORGANIZER.value"]; +event["X-ADITO-ISALLDAYEVENT"] = fields["ALLDAY.value"]; if(fields["RRULE.value"]) +{ event[calendars.RRULE] = [fields["RRULE.value"]]; +} if (fields["REMINDER.value"]) { event[calendars.HASREMINDER] = "true"; event[calendars.REMINDER_DURATION] = fields["REMINDER.value"]; } - -var idstringarray = calendars.insert([event]); - -if(event["LINKS"]) -{ - event["LINKS"].forEach(function(pLink){ - neon.addRecord("AppointmentLinks", - { - "OBJECTID" : pLink["OBJECT_ID"], - "OBJECTTYPE" : pLink["OBJECT_TYPE"], - "APPOINTMENT_ID" : idstringarray[0] - }); - }) -} - -event[calendars.ID] = idstringarray[0]; +event[calendars.ID] = calendars.insert([event])[0]; neon.setFieldValue("$field.UID", event[calendars.ID]); vars.set("$context.editmode", calendars.MODE_UPDATE); diff --git a/entity/DocumentTemplate_entity/entityfields/openhtmleditor/stateProcess.js b/entity/DocumentTemplate_entity/entityfields/openhtmleditor/stateProcess.js index c0824ad21cb8d86f3e4cd4b0729d393cb7db7870..718a96109027807c05614a94925ff71302ec524c 100644 --- a/entity/DocumentTemplate_entity/entityfields/openhtmleditor/stateProcess.js +++ b/entity/DocumentTemplate_entity/entityfields/openhtmleditor/stateProcess.js @@ -7,5 +7,12 @@ import("system.neon"); var template = DocumentTemplateUtils.getTemplate(vars.get("$field.DOCUMENTTEMPLATEID"), false); var kind = vars.get("$field.KIND"); -if(template.type == DocumentTemplate.types.HTML && kind == $KeywordRegistry.documentTemplateType$textModular() || kind == $KeywordRegistry.documentTemplateType$mail()) - result.string(neon.COMPONENTSTATE_EDITABLE); +if (template) +{ + if(template.type == DocumentTemplate.types.HTML && + kind == $KeywordRegistry.documentTemplateType$textModular() || + kind == $KeywordRegistry.documentTemplateType$mail()) + { + result.string(neon.COMPONENTSTATE_EDITABLE); + } +} diff --git a/entity/Email_entity/entityfields/sendmail/onActionProcess.js b/entity/Email_entity/entityfields/sendmail/onActionProcess.js index 0ee0af9d3e78ea7027cafebd667d54814c15e43c..8c93bbcfad19c8a77e2d8aa228f336723f2b466c 100644 --- a/entity/Email_entity/entityfields/sendmail/onActionProcess.js +++ b/entity/Email_entity/entityfields/sendmail/onActionProcess.js @@ -30,7 +30,7 @@ if (vars.exists("$param.AdditionalPlaceholders_param") && vars.get("$param.Addit }); } -var eml = EmailWritingUtils.openMailTemplate( +EmailWritingUtils.openMailTemplate( vars.get("$field.RECIPIENT"), EmployeeUtils.getCurrentContactId(), vars.get("$field.DOCUMENT_TEMPLATE"), diff --git a/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js b/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js index 0c453f91c3e8e31847be4c6cca575257597a7650..69b7b7b8cb88c489754264203262574b6ff4e2be 100644 --- a/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js +++ b/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js @@ -33,6 +33,4 @@ if (template) } ActivityUtils.createNewActivity(null, links, null, null, translate.text("Letter"), text.parseDocument(content), $KeywordRegistry.activityDirection$outgoing(), [[template.filename, content, false]]); -} -else - throw new Error("Error while using a document template: The provided template does not contain data."); \ No newline at end of file +} \ No newline at end of file diff --git a/entity/Offer_entity/entityfields/contact_id/stateProcess.js b/entity/Offer_entity/entityfields/contact_id/stateProcess.js index e51ff93affb4e84e12bff1e0a4a0145c88fc2dd2..0dcccb84c7750c4743ac3fb30a625052af4e8830 100644 --- a/entity/Offer_entity/entityfields/contact_id/stateProcess.js +++ b/entity/Offer_entity/entityfields/contact_id/stateProcess.js @@ -3,4 +3,11 @@ import("system.result"); import("system.neon"); import("system.vars"); -result.string(OfferUtils.isEditable(vars.get("$field.STATUS")) ? neon.COMPONENTSTATE_AUTO : neon.COMPONENTSTATE_DISABLED); +if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT) +{ + result.string(neon.COMPONENTSTATE_READONLY); +} +else +{ + result.string(OfferUtils.isEditable(vars.get("$field.STATUS")) ? neon.COMPONENTSTATE_AUTO : neon.COMPONENTSTATE_DISABLED); +} diff --git a/entity/Organisation_entity/Organisation_entity.aod b/entity/Organisation_entity/Organisation_entity.aod index b8e0c8e551c964283d0876a372462282547610c8..be40c333adc19fbc28ccd8715d0596b2f151a47f 100644 --- a/entity/Organisation_entity/Organisation_entity.aod +++ b/entity/Organisation_entity/Organisation_entity.aod @@ -1436,6 +1436,7 @@ <title>New appointment</title> <onActionProcess>%aditoprj%/entity/Organisation_entity/entityfields/newappointment/onActionProcess.js</onActionProcess> <iconId>VAADIN:CALENDAR</iconId> + <state>EDITABLE</state> <stateProcess>%aditoprj%/entity/Organisation_entity/entityfields/newappointment/stateProcess.js</stateProcess> <tooltip>New Appointment</tooltip> </entityActionField> diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod index f294673d397ad7e5b12ab7f16821daa5d3c0d75b..d318ebbdde32ccfe73c757d1e904246333556526 100644 --- a/entity/Person_entity/Person_entity.aod +++ b/entity/Person_entity/Person_entity.aod @@ -1453,6 +1453,7 @@ <title>New appointment</title> <onActionProcess>%aditoprj%/entity/Person_entity/entityfields/newappointment/onActionProcess.js</onActionProcess> <iconId>VAADIN:CALENDAR</iconId> + <state>EDITABLE</state> <stateProcess>%aditoprj%/entity/Person_entity/entityfields/newappointment/stateProcess.js</stateProcess> <tooltip>New Appointment</tooltip> </entityActionField> diff --git a/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/onActionProcess.js b/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/onActionProcess.js index b760e1613d9594960cabd2067bade94a03105560..6de5e67211d4a10723765b058e83b58c8cdf6530 100644 --- a/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/onActionProcess.js +++ b/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/onActionProcess.js @@ -25,12 +25,10 @@ var summary = translate.text("Site visit") + " || " + fullName; var description = fullName; var standardMail = CommUtil.getStandardMail(selectionRowData[0].CONTACT_ID); -var startTime = selectionRowData[0].BEGIN_TIME; -var endTime = selectionRowData[0].END_TIME; -var duration = eMath.subInt(endTime, startTime); -var entryDate = datetime.toLocaleDate(selectionRowData[0].ENTRYDATE, "dd-MM-yyyy"); -startTime = entryDate + " " + datetime.toLocaleDate(selectionRowData[0].BEGIN_TIME, "HH:mm:ss.S"); -startTime = datetime.toLong(startTime, "dd-MM-yyyy HH:mm:ss.S", "UTC"); // #1076044 set tz to prevent time gaps. +//creates an js date object with the current utc time and adds the appointment begin/end time. +//necessary for CalendarUtil.createEntry() +var start = new Date(datetime.today(vars.get("$sys.timezone"))+Number(selectionRowData[0].BEGIN_TIME)); +var end = new Date(datetime.today(vars.get("$sys.timezone"))+Number(selectionRowData[0].END_TIME)); var links = [ { @@ -44,8 +42,8 @@ var links = [ ]; var params = { - "Entry_param": JSON.stringify(CalendarUtil.createEntry(summary, description, links, undefined, undefined, Date(Date.toExponential(startTime)), - Date(Date.toExponential(endTime)), undefined, undefined, undefined, [standardMail], + "Entry_param": JSON.stringify(CalendarUtil.createEntry(summary, description, links, undefined, undefined, start, + end, undefined, undefined, undefined, [standardMail], undefined, undefined, undefined)) }; diff --git a/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/stateProcess.js b/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/stateProcess.js index 3f986eb99cdd8c56ea85788bc2ab0f547f172b25..181e70bbeca24bebbcad6595818e49b2e55484ad 100644 --- a/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/stateProcess.js +++ b/entity/VisitPlanEntry_entity/entityfields/entityactiongroup/children/newappointment/stateProcess.js @@ -2,9 +2,14 @@ import("system.logging"); import("system.result"); import("system.vars"); import("system.neon"); +import("Util_lib"); -if (vars.get("$field.ISGROUP") == "false" && vars.get("$sys.selectionRows") != "" +if (Utils.toBoolean(vars.get("$field.ISGROUP")) && (vars.get("$field.STATUS") == "VISITSTATUSAPPPLANED" - || vars.get("$field.STATUS_APPOINTMENT") == "VISITSTATUSAPPOINTMENTCONFIRMED ")) - result.string(neon.COMPONENTSTATE_DISABLED); + || vars.get("$field.STATUS_APPOINTMENT") == "VISITSTATUSAPPOINTMENTCONFIRMED ") + || Utils.isNullOrEmpty(vars.get("$sys.selectionRows")) + || Utils.isNullOrEmpty(vars.get("$field.PARENT_ID"))) +{ + result.string(neon.COMPONENTSTATE_DISABLED); +} diff --git a/process/CalendarUtil_test/CalendarUtil_test.aod b/process/CalendarUtil_test/CalendarUtil_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..003d70031c462bade2eda8dbf49aa510a48faf9f --- /dev/null +++ b/process/CalendarUtil_test/CalendarUtil_test.aod @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2"> + <name>CalendarUtil_test</name> + <title>[TEST] Calendar_lib</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/CalendarUtil_test/process.js</process> + <alias>Data_alias</alias> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/CalendarUtil_test/process.js b/process/CalendarUtil_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..6c1808870af916388b07ef1d865e2658de2ff71f --- /dev/null +++ b/process/CalendarUtil_test/process.js @@ -0,0 +1,82 @@ +import("system.calendars"); +import("system.result"); +import("system.db"); +import("UnitTest_lib"); +import("Calendar_lib"); +import("Sql_lib"); + + +var testUids = []; +var tester = new Tester("Test Calendar_lib"); +var newSilentEvent = new TestSuite("CalendarUtil.newSilentEvent", [ + new Test("Should create an appointment without graphical user interaction.", function(pTester, pDataProvider){ + var uid = CalendarUtil.newSilentEvent(pDataProvider[0], pDataProvider[1], pDataProvider[2], pDataProvider[3], pDataProvider[4], + pDataProvider[5], pDataProvider[6], pDataProvider[7], pDataProvider[8], pDataProvider[9], pDataProvider[10], pDataProvider[11], + pDataProvider[12], pDataProvider[13]); + + var doesLinksExists; + var doesExists = Number(newSelect("count(*)", SqlUtils.getSystemAlias()) + .from("asys_calendarbackend") + .where("asys_calendarbackend.elementuid", uid) + .cell()); + + pTester.expectThat(doesExists).isGreaterEqual(1).assert(); + + if(pDataProvider[2] && doesExists) + { + doesLinksExists = newSelect("ab_appointmentlink_id") + .from("ab_appointmentlink") + .where("ab_appointmentlink.appointment_id", uid) + .arrayColumn(); + + pTester.expectThat(doesLinksExists).hasMinLength(1).assert(); + } + + doesLinksExists.length > 0 ? testUids.push([uid, doesLinksExists]) : testUids.push([uid]); + }, function(){ + return [ + ["Testtermin 1","Testbeschreibung",[{"OBJECT_ID":"c7ddf982-0e58-4152-b82b-8f5673b0b729", "OBJECT_TYPE":"Person"}], "Admin", ["Admin"], + new Date("2021", "02", "29", "08", "30"), new Date("2021", "02", "29", "08", "45"), ["Meeting"], undefined, undefined, undefined, + "Microsoft Teams", false, calendars.CLASSIFICATION_PUBLIC], + ["Testtermin 2","Testbeschreibung", + [{"OBJECT_ID":"c7ddf982-0e58-4152-b82b-8f5673b0b729", "OBJECT_TYPE":"Person"}, + {"OBJECT_ID":"18ed06df-30b2-4d59-a4b4-a6e646f6f05a", "OBJECT_TYPE":"Activity"}, + {"OBJECT_ID":"449080f6-b714-4189-a261-37439d0d4010", "OBJECT_TYPE":"Organisation"}, + {"OBJECT_ID":"e9cb198d-c420-4192-9c29-b23682457d8e", "OBJECT_TYPE":"Task"}], + "Admin", ["Admin"], new Date("2021", "03", "08", "14", "30"), new Date("2021", "03", "08", "15", "45"), ["Meeting", "OutOfOffice"], + calendars.STATUS_ACCEPTED, new Date("2021", "03", "08", "14", "15"), + ["herbert.obermaier@hotmail.de", "lisa.lustig@yahoo.com"], "Microsoft Teams", false, calendars.CLASSIFICATION_PUBLIC], + ["Testtermin 3","Testbeschreibung",null, "Admin", ["Admin"], + new Date("2021", "03", "29", "10", "00"), new Date("2021", "03", "29", "11", "00"), ["Vacation"], undefined, undefined, undefined, + "Microsoft Teams", false, calendars.CLASSIFICATION_PUBLIC], + ["Testtermin 4","Testbeschreibung",[{"OBJECTID": "d8f35764-2c56-45be-93c7-f1e0695e2417", "OBJECT_TYPE":"Task"}], "Admin", ["Admin"], + new Date("2021", "03", "29", "10", "00"), new Date("2021", "03", "29", "11", "00"), ["Vacation"], undefined, undefined, undefined, + "Microsoft Teams", false, calendars.CLASSIFICATION_PUBLIC], + ]; + }) +], null, null, function(){ + for (i = 0; i < testUids.length; i++) + { + if(testUids[i].length > 1) + { + newWhere("asys_calendarbackend.elementuid", testUids[i][0], null, null, SqlUtils.getSystemAlias()) + .deleteData(); + testUids[i][1].forEach(function(pLinkUid){ + newWhere("ab_appointmentlink.ab_appointmentlink_id", pLinkUid, null, null, db.getCurrentAlias()) + .deleteData(); + }); + } + else + { + newWhere("asys_calendarbackend.elementuid", testUids[i][0], null, null, SqlUtils.getSystemAlias()) + .deleteData(); + } + } +}); + +tester.initCoverage(CalendarUtil); +tester.test(newSilentEvent); + +tester.summary(); + +result.object(tester.getResults()); \ No newline at end of file diff --git a/process/Calendar_lib/process.js b/process/Calendar_lib/process.js index 455b28d263c1e6def680391206245b213240c4e8..de9bc373d0fee6098f61111dfa3ae96f8c5ab735 100644 --- a/process/Calendar_lib/process.js +++ b/process/Calendar_lib/process.js @@ -1,657 +1,658 @@ -import("system.translate"); -import("system.datetime"); -import("system.neon"); -import("system.calendars"); -import("system.vars"); -import("system.db"); -import("system.swing"); -import("system.eMath"); -import("system.logging"); -import("system.tools"); -import("system.text"); -import("system.question"); -import("system.SQLTYPES"); -import("system.result"); -import("system.util"); -import("system.entities"); -import("Util_lib"); -import("Sql_lib"); - - -/** - * Functions for the calendar. - * <p> - * <b><u>Do not create an instance of this!</u></b> - * @class - */ -function CalendarUtil(){} - - -/* - * Creates and opens an new task object (with link). - * - * @param {String} pSummary (optional) <p> - * The summary.<br> - * @param {String} pDescription (optional) <p> - * The description.<br> - * @param {Boolean} pWithLink (optional) Case if its true, then an a shortcut to $image.frametable will created.<br> - * @param {String[][]} pWithLink (optional) <p> - * The required informations:<br> - * <ul> - * <li>pWithLink[0]: Name of the frame.</li> - * <li>pWithLink[1]: Id of the shown record.</li> - * <li>pWithLink[2]: Linking title.</li> - * @param {String} pUser (optional) <p> - * The user (login).<br> - * @param {[]} pAffectedUsers (optional) <p> - * The affected users. (login)<br> - * @param {date} pStart (optional) <p> - * Start of the task.<br> - * @param {date} pDuration (optional) <p> - * Duration of the task.<br> - * @param {integer} pCategory (optional) <p> - * calendars.CATEGORIES , encoded(String) (e.g.: text.encodeMS(["Service"])) - * @param {String} pStatus (optional) <p> - * Status of the appointment. (calendars.STATUS_TENTATIVE, <br> - * calendars.STATUS_CONFIRMED, calendars.STATUS_CANCELLED)<br> - * @param {Array{[]} pComps4Refresh (optional) <p> - * The component which will be updated.<br> - * - * @return {void} - */ -CalendarUtil.newTodo = function(pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus, pComps4Refresh) -{ - var todo = CalendarUtil.createEntry( calendars.VTODO, pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus ); - var prompts = []; - prompts["comp4refresh"] = []; - - if (pComps4Refresh == undefined) - pComps4Refresh = ["$comp.Aufgabe", "$comp.tbl_Aufgabe"]; - - for (var i = 0; i < pComps4Refresh.length; i++) - { - if ( vars.exists(pComps4Refresh[i])) prompts["comp4refresh"].push(pComps4Refresh[i]); - } - if(vars.getString("$sys.scope") == "vaadin") - neon.openCalendarEntry([todo], null, neon.OPERATINGSTATE_NEW, null) - else - { - if (vars.exists("$sys.currentwindow")) - prompts["window"] = vars.getString("$sys.currentwindow"); - if (vars.exists("$sys.currentimage")) - prompts["image"] = vars.getString("$sys.currentimage"); - - swing.openCalendarEntry([todo], null, false, prompts); - } -} - - -/** - * Finds the effective calendarId of an user in the same <br> - * attribute order like the ADITO core, which is:<br> - * <p> - * exchangeEmail -> calendarID -> email<br> - * <p> - * <b><u>DO NOT CHANGE THIS ORDER!</u></b> - * - * @param {String} pUser <p> - * To check. - * @return <p> - * Effective calendar id.<br> - */ -CalendarUtil.getEffectiveCalendarIdFromUser = function(pUser) -{ - var userParams = pUser["params"]; - - var resolvedCurrentUser; - var exchangeEmail = userParams["exchangeEMail"]; - var calendarId = userParams["calendarID"]; - var email = userParams["email"]; - - if(exchangeEmail) - return exchangeEmail; - else if(calendarId) - return calendarId; - else if(email) - return email; - else - return ""; -} - - -/* - * Creates and opens an new appointment object (with link). - * - * @param {String} pSummary (optional) <p> - * The summary.<br> - * @param {String} pDescription (optional) <p> - * The description.<br> - * @param {Boolean} pWithLink (optional) <p> - * True sets an link to $image.frametable<br> - * @param {String[][]} pWithLink (optional) Description:<br> - * <ul> - * <li>pWithLink[0]: Name of the frame</li> - * <li>pWithLink[1]: Id of the shown record</li> - * <li>pWithLink[2]: linking title</li> - * </ul> - * @param {String} pUser (optional) <p> - * The user (login). - * @param {[]} pAffectedUsers (optional) <p> - * The affected users (login). - * @param {Date} pStart (optional) <p> - * Begin of the task.<br> - * @param {Date} pDuration (optional) <p> - * Duration.<br> - * @param {Number} pCategory (optional) <p> - * calendars.CATEGORIES , encoded(String) (z.B.: text.encodeMS(["Service"])).<br> - * @param {String} pStatus (optional) <p> - * Status of the appointment:<br> - * <ul> - * <li>calendars.STATUS_TENTATIVE</li> - * <li>calendars.STATUS_CONFIRMED</li> - * <li>calendars.STATUS_CANCELLED</li> - * </ul> - * @param {Array{[]} pComps4Refresh (optional) <p> - * The component which will be updated.<br> - * @param {Array{[]} pWorklistId (optional) <p> - * The worklist id.<br> - * - * @return {void} - */ -CalendarUtil.newEvent = function( pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus, pComps4Refresh, pWorklistId) -{ - var event = CalendarUtil.createEntry( calendars.VEVENT, pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus ); - - var prompts = []; - prompts["comp4refresh"] = []; - if (pComps4Refresh == undefined) - pComps4Refresh = ["$comp.Aufgabe", "$comp.tbl_Termine"]; - for (let i = 0; i < pComps4Refresh.length; i++) - { - if ( vars.exists(pComps4Refresh[i])) prompts["comp4refresh"].push(pComps4Refresh[i]); - } - - if(vars.getString("$sys.scope") == "vaadin") - neon.openCalendarEntry([event],"", neon.OPERATINGSTATE_NEW, null) - else - { - prompts["window"] = vars.getString("$sys.currentwindow"); - prompts["image"] = vars.getString("$sys.currentimage"); - if (pWorklistId != undefined) - prompts["worklistId"] = pWorklistId; - swing.openCalendarEntry([event], null, false, prompts); - } -} - - -/* - * Creates an new appointment entry. - * - * @param {String} pSummary (optional) <p> - * The summary/title of the appointment. - * @param {String} pDescription (optional) <p> - * The appointment description. - * @param {String} pLinks (optional) <p> - * The links as objects <u>(key: "OBJECT_ID" & "OBJECT_TYPE")</u> in an array. - * @param {String} pOwner (optional) <p> - * The calendar-user (username) which will be specified as entry-owner. - * @param {String[]} pAffectedUsers (optional) <p> - * The affected users (username). - * @param {Date} pStart (optional) <p> - * The start of the appointment. - * @param {Date} pEnd (optional) <p> - * The end of the appointment. - * @param {String[]} pCategories (optional) <p> - * The categories of the appointment, the default ones are:<br> - * <ul> - * <li>Meeting</li> - * <li>Organisation</li> - * <li>OutOfOffice</li> - * <li>Vacation</li> - * </ul> - * @param {String} pStatus (optional) <p> - * Status of the appointment:<br> - * <ul> - * <li>calendars.STATUS_TENTATIVE</li> - * <li>calendars.STATUS_CONFIRMED</li> - * <li>calendars.STATUS_CANCELLED</li> - * </ul> - * @param {Date} pReminder (optional) <p> - * Date of the reminder for the appointment. - * @param {String[]} pExternalAttendees (optional) <p> - * External attendees. - * @param {String} pLocation (optional) <p> - * The location of the appointment. - * @param {Boolean} pIsAllDay (optional) <p> - * Whether if it is an all-day appointment or not. - * @param {String} pClassification (optional) <p> - * The classification of the appointment:<br> - * <ul> - * <li>calendars.CLASSIFICATION_PUBLIC</li> - * <li>calendars.CLASSIFICATION_PRIVATE</li> - * </ul> - * @return {void} - */ -CalendarUtil.newSilentEvent = function(pSummary, pDescription, pLinks, pOwner, pAffectedUsers, pStart, pEnd, pCategories, pStatus, - pReminder, pExternalAttendees, pLocation, pIsAllDay, pClassification) -{ - var event = CalendarUtil.createEntry(pSummary, pDescription, pLinks, pOwner, pAffectedUsers, pStart, pEnd, pCategories, pStatus, pReminder, - pExternalAttendees, pLocation, pIsAllDay, pClassification); - - var ids = calendars.insert([event], calendars.GROUP_SINGLE); - - if(pLinks) - { - var conf; - - pLinks.forEach(function(pLink){ - conf = entities.createConfigForAddingRows().entity("AppointmentLink_entity").fieldValues({ - "APPOINTMENT_ID" : ids[0], - "OBJECTID" : pLink["OBJECT_ID"], - "OBJECTTYPE" : pLink["OBJECT_TYPE"] - }); - - entities.createRow(conf); - }); - } -} - -/* - * Creates an new appointment object, which is responsible for holding the data<br> - * till it's used to insert with: calendars.insert (e.g.: in Appointment_entity). - * - * @param {String} pSummary (optional) <p> - * The summary/title of the appointment. - * @param {String} pDescription (optional) <p> - * The description of the appointment. - * @param {Object[]} pLinks (optional) <p> - * The links as objects <u>(key: "OBJECT_ID" & "OBJECT_TYPE")</u> in an array. - * @param {String} pOwner (optional) <p> - * The calendar-user (username) which will be specified as entry-owner. - * @param {String[]} pAffectedUsers (optional) <p> - * The affected users (usernames), which will be added to the appointment. - * @param {Date} pStart (optional) <p> - * Start of the appointment. - * @param {Date} pEnd (optional) <p> - * Duration of the appointment. - * @param {String[]} pCategories (optional) <p> - * The categories of the appointment, the default ones are:<br> - * <ul> - * <li>Meeting</li> - * <li>Organisation</li> - * <li>OutOfOffice</li> - * <li>Vacation</li> - * </ul> - * @param {String} pStatus (optional) Status of the appointment:<br> - * <ul> - * <li>calendars.STATUS_TENTATIVE</li> - * <li>calendars.STATUS_CONFIRMED</li> - * <li>calendars.STATUS_CANCELLED</li> - * </ul> - * @param {Date} pReminder (optional) <p> - * Date of reminder. - * @param {String[]} pExternalAttendees (optional) <p> - * External attendes (e-mail addresses). - * @param {String} pLocation (optional) <p> - * The locations of the appointment. - * @param {Boolean} pIsAllDay (optional) <p> - * Whether if it is an all-day appointment or not. - * @param {String} pClassification (optional) <p> - * The classification of the appointment: - * <ul> - * <li>calendars.CLASSIFICATION_PUBLIC</li> - * <li>calendars.CLASSIFICATION_PRIVATE</li> - * </ul> - * @return {Object} - */ -CalendarUtil.createEntry = function(pSummary, pDescription, pLinks, pOwner, pAffectedUsers, pStart, pEnd, pCategories, pStatus, - pReminder, pExternalAttendees, pLocation, pIsAllDay, pClassification) -{ - var entry = {}; - - entry[calendars.TYPE] = calendars.VEVENT; // hardcoded, cause only other option would be calendars.VTODO for an task - // since tasks are handled via. Task_entity there is no need for the calendars.VTODO option. - - if (!pDescription) - { - if(vars.getString("$sys.scope") == "vaadin") - { - pDescription = neon.getImageContent(vars.getString("$sys.currententityname")); - } - else - { - pDescription = swing.getImageContent(); //todo: check whether it's necessary or not. #1047482 - } - } - - if (!pOwner) - { - pOwner = vars.getString("$sys.user"); - } - - if (!pStart) - { - entry[calendars.DTSTART] = Date.now(); - } - else - { - entry[calendars.DTSTART] = pStart.getTime(); - } - - if (!pEnd) - { - let tempStartdate = entry[calendars.DTSTART]; - entry[calendars.DTEND] = tempStartdate.setHours(tempStartdate.getHours()+1); - } - else - { - entry[calendars.DTEND] = pEnd.getTime().toString(); - } - - if (!pCategories || pCategories == []) - { - pCategories = ""; - } - else - { - for (i = 0; i < pCategories.length; i++) - { - pCategories[i] = translate.text(pCategories[i]); - } - - pCategories = text.encodeMS(pCategories); - } - - if ((pAffectedUsers == null || pAffectedUsers == undefined) && (pExternalAttendees == null || pExternalAttendees == undefined)) - { - entry[calendars.AFFECTEDUSERS] = ""; - } - else - { - var affectedUsers = []; - - if(pAffectedUsers && pAffectedUsers != []) - { - affectedUsers = calendars.getCalendarUsers(pAffectedUsers); - } - - if(pExternalAttendees && pExternalAttendees != []) - { - for(let i = 0; i < pExternalAttendees.length; i++) - { - affectedUsers.push("; mailto:" + pExternalAttendees[i] + "; CN:" + pExternalAttendees[i] + "; ") - } - } - - entry[calendars.AFFECTEDUSERS] = text.encodeMS(affectedUsers); - } - - if (!pStatus) - { - pStatus = calendars.STATUS_CONFIRMED; - } - - if(!pReminder) - { - entry[calendars.HASREMINDER] = "true"; - entry[calendars.REMINDER_DURATION] = pReminder.getTime().toString(); - } - else - { - entry[calendars.HASREMINDER] = "false"; - } - - if(pLinks) - { - entry["LINKS"] = pLinks; - } - - entry[calendars.USER] = calendars.getCalendarUser(pOwner); - entry[calendars.DESCRIPTION] = pDescription; - entry[calendars.SUMMARY] = pSummary || ""; - entry[calendars.STATUS] = CalendarUtil.mapCalendarStatus(pStatus, calendars.getBackendType()); - entry[calendars.CLASSIFICATION] = pClassification || calendars.CLASSIFICATION_PUBLIC; - entry[calendars.CATEGORIES] = pCategories; - entry[calendars.TRANSPARENCY] = "OPAQUE"; - entry[calendars.LOCATION] = pLocation || ""; - entry["X-ADITO-ISALLDAYEVENT"] = pIsAllDay ? "TRUE" : "FALSE"; - entry[calendars.DTSTART] = entry[calendars.DTSTART].toString(); - - return entry; -} - -/* - * Add an condition.<br> - * - * @param {[]} pConditions <p> - * The condition.<br> - * @param {Integer} pIndex <p> - * Index of the condition.<br> - * @param {Object} pValues <p> - * The values.<br> - * @return {void} - */ -CalendarUtil.addEntryCondition = function(pConditions, pIndex, pValues) -{ - var params = ["TYPE", "START", "END", "USER", "STATUS", "UID"]; - - for (var i = 0; i < params.length; i++) - if (pValues[params[i]] != undefined) pConditions[params[i] + "_" + pIndex] = pValues[params[i]]; -} - -/* - * Returns the date without the time.<br> - * - * @param {String} datetimeIn <p> - * Datetime.<br> - * @return {Date} <p> - * The desired date.<br> - */ -CalendarUtil.getDate = function(datetimeIn) -{ - if ( datetimeIn != "") - return datetime.clearTime(datetimeIn); - else return ""; -} - -/* - * Resets the event filter.<br> - * - * @return {Object} - */ -CalendarUtil.reset_filterEvent = function() -{ - var today = CalendarUtil.getDate(vars.getString("$sys.date")); - - return pFilter = { - user: vars.getString("$sys.user"), - datefrom: String(today), //nur die Termine ab heute anzeigen, - //die von vor einer Woche sind uninteressant - dateto: String(eMath.addInt(eMath.addInt(today, datetime.ONE_WEEK) - ,datetime.ONE_DAY - datetime.ONE_MINUTE)), - category: "", - tentative: "true", - confirmed: "true", - cancelled: "", - free: "true" - }; -} - -/* - * Gibt den richtigen Status zum Prüfen je nach Backend zurück - * Returns the matching status, to the corresponding backend. - * - * - * @param {String} pStatus req die konstante für den zu prüfenden status, - * z.B. calendars.STATUS_INPROCESS - * - * @param {String} pCalendarType req die konstante für den typen des Termin- oder Aufgabenbackends, - * z.B. calendars.BACKEND_DB - * - * @return {String} Konstanten für den Kalender (Backend-Typen), gibt es den status im backend nicht - * wird null geliefert - */ -CalendarUtil.mapCalendarStatus = function(pStatus, pCalendarType) -{ - switch (pCalendarType) - { - //case calendars.BACKEND_EXCHANGE: - case calendars.BACKEND_EXCHANGEWS: - if (pStatus == calendars.STATUS_CONFIRMED) - return calendars.STATUS_BUSY; - else - return pStatus; - default: - if (pStatus == calendars.STATUS_OOF)//nur bei exchange - return null; - else - return pStatus; - } -} - -/** - * Returns the "real" calendar system/backend type<br> - * (e.g.: BackendType & SyncBackendType) - * - * @param {Number} pScope <p> - * The needed scope:<br> - * <ul> - * <li>calendars.VEVENT</li> - * <li>calendars.VTODO</li> - * </ul> - * @return {Number} <p> - * The backend type (e.g.: calendars.BACKEND_*).<br> - */ -CalendarUtil.getCalendarSystemType = function(pScope) -{ - // Check sync backend type - if (calendars.getSyncBackendType() != calendars.BACKEND_NONE && calendars.getSyncBackendType() != 3) - { - var scope = calendars.getSyncBackendTypeScope(); - if (scope.length == 1 && scope[0] == pScope) // Scope.length = 1 -> VEVENT *OR* VTODO - return calendars.getSyncBackendType(); - else if (scope.length == 2) // Scope.length = 2 -> Both - return calendars.getSyncBackendType(); - // Scope.length = 0 -> Nothing selected -> Skip this block - } - - // Fallback to backend type (event) - if (calendars.getBackendType() != calendars.BACKEND_NONE && pScope === calendars.VEVENT) - return calendars.getBackendType(); - - // Second fallback to backend type (todo) - if (calendars.getBackendTypeTasks() != calendars.BACKEND_NONE && pScope === calendars.VTODO) - return calendars.getBackendTypeTasks(); - - // Everything is none - return calendars.BACKEND_NONE; -} - -CalendarUtil.buildEntriesFromUids = function(appointmentUids) -{ - var entryArray = new Array(appointmentUids.length); - - for(var i = 0; i < appointmentUids.length; i++) - { - var hasPermission = true; - - if(vars.get("$param.ErrorOnPermissionDenied") == "false" || vars.getString("$param.LinkedAppointmentsFromDashlet_param")) - hasPermission = hasUserPermissionForReadingEntry(getEntryOwnerCn(appointmentUids[i])); - - if(hasPermission) - entryArray[i] = CalendarUtil.buildEntry(calendars.getEntry(appointmentUids[i], null, null), null); - } - - //filter out all null - var filteredEntryArray = entryArray.filter(function (el) { - return el != null; - }); - - return filteredEntryArray; -} - - -CalendarUtil.countEntriesFromUids = function(appointmentUids) -{ - return CalendarUtil.buildEntriesFromUids(appointmentUids).length; -} - -CalendarUtil.buildEntry = function (pEntry, pMasterentry) -{ - var uid = pEntry[calendars.ID]; - var summary = pEntry[calendars.SUMMARY]; - var attendees = pEntry[calendars.AFFECTEDUSERS]; - var startdate = pEntry[calendars.DTSTART]; - var enddate = pEntry[calendars.DTEND]; - var links = pEntry[calendars.LINKS]; - var description = pEntry[calendars.DESCRIPTION]; - if(pEntry[calendars.ORGANIZER2] != undefined) - var organizer = pEntry[calendars.ORGANIZER2]["paramvalue"]; - if(pEntry[calendars.USER2] != undefined) - var owner = JSON.stringify(pEntry[calendars.USER2]); - var status = pEntry[calendars.STATUS]; - var location = pEntry[calendars.LOCATION]; - var reminder = pEntry[calendars.REMINDER_DURATION]; - var remindercheck = pEntry[calendars.HASREMINDER] - var classification = pEntry[calendars.CLASSIFICATION]; - var transparency = pEntry[calendars.TRANSPARENCY]; - var categories = pEntry[calendars.CATEGORIES]; - var isAllDay = pEntry["X-ADITO-ISALLDAYEVENT"] != null ? pEntry["X-ADITO-ISALLDAYEVENT"] : "FALSE"; - - var masterBegin = pMasterentry != null ? pMasterentry[calendars.DTSTART] : null - var masterEnd = pMasterentry != null ? pMasterentry[calendars.DTEND] : null - - // Recurrence - var recurrenceID = pEntry[calendars.RECURRENCEID]; - var rrule = null; - if (pMasterentry != null) { // Entry is a recurrence exception, therefore get rrule from master - rrule = pMasterentry[calendars.RRULE] != null ? pMasterentry[calendars.RRULE][0] : null; - } else { - rrule = pEntry[calendars.RRULE] != null ? pEntry[calendars.RRULE][0] : null; - } - - return [ - uid, - attendees.length, - startdate, - enddate, - summary, - organizer, - owner, - attendees, - status, - description, - location, - '', - isAllDay, - classification, - transparency, - categories, - reminder, - remindercheck, - rrule, - recurrenceID, - null, - masterBegin, - masterEnd, - null - ]; -} - - -function hasUserPermissionForReadingEntry(calUserCn) -{ - return calendars.hasPermission(calUserCn, calendars.VEVENT, "READ"); -} - -function getEntryOwnerCn(appointmentUid) -{ - - var owner = newSelect("ASYS_CALENDARBACKEND.OWNER", "_____SYSTEMALIAS") - .from("ASYS_CALENDARBACKEND") - .whereIfSet("ASYS_CALENDARBACKEND.ELEMENTUID", appointmentUid) - .cell(true); - - var ownerArr = text.decodeMS(owner); - return ownerArr[1].split(":")[1]; +import("system.translate"); +import("system.datetime"); +import("system.neon"); +import("system.calendars"); +import("system.vars"); +import("system.db"); +import("system.swing"); +import("system.eMath"); +import("system.logging"); +import("system.tools"); +import("system.text"); +import("system.question"); +import("system.SQLTYPES"); +import("system.result"); +import("system.util"); +import("system.entities"); +import("Util_lib"); +import("Sql_lib"); + + +/** + * Functions for the calendar. + * <p> + * <b><u>Do not create an instance of this!</u></b> + * @class + */ +function CalendarUtil(){} + + +/* + * Creates and opens an new task object (with link). + * + * @param {String} pSummary (optional) <p> + * The summary.<br> + * @param {String} pDescription (optional) <p> + * The description.<br> + * @param {Boolean} pWithLink (optional) Case if its true, then an a shortcut to $image.frametable will created.<br> + * @param {String[][]} pWithLink (optional) <p> + * The required informations:<br> + * <ul> + * <li>pWithLink[0]: Name of the frame.</li> + * <li>pWithLink[1]: Id of the shown record.</li> + * <li>pWithLink[2]: Linking title.</li> + * @param {String} pUser (optional) <p> + * The user (login).<br> + * @param {[]} pAffectedUsers (optional) <p> + * The affected users. (login)<br> + * @param {date} pStart (optional) <p> + * Start of the task.<br> + * @param {date} pDuration (optional) <p> + * Duration of the task.<br> + * @param {integer} pCategory (optional) <p> + * calendars.CATEGORIES , encoded(String) (e.g.: text.encodeMS(["Service"])) + * @param {String} pStatus (optional) <p> + * Status of the appointment. (calendars.STATUS_TENTATIVE, <br> + * calendars.STATUS_CONFIRMED, calendars.STATUS_CANCELLED)<br> + * @param {Array{[]} pComps4Refresh (optional) <p> + * The component which will be updated.<br> + * + * @return {void} + */ +CalendarUtil.newTodo = function(pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus, pComps4Refresh) +{ + var todo = CalendarUtil.createEntry( calendars.VTODO, pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus ); + var prompts = []; + prompts["comp4refresh"] = []; + + if (pComps4Refresh == undefined) + pComps4Refresh = ["$comp.Aufgabe", "$comp.tbl_Aufgabe"]; + + for (var i = 0; i < pComps4Refresh.length; i++) + { + if ( vars.exists(pComps4Refresh[i])) prompts["comp4refresh"].push(pComps4Refresh[i]); + } + if(vars.getString("$sys.scope") == "vaadin") + neon.openCalendarEntry([todo], null, neon.OPERATINGSTATE_NEW, null) + else + { + if (vars.exists("$sys.currentwindow")) + prompts["window"] = vars.getString("$sys.currentwindow"); + if (vars.exists("$sys.currentimage")) + prompts["image"] = vars.getString("$sys.currentimage"); + + swing.openCalendarEntry([todo], null, false, prompts); + } +} + + +/** + * Finds the effective calendarId of an user in the same <br> + * attribute order like the ADITO core, which is:<br> + * <p> + * exchangeEmail -> calendarID -> email<br> + * <p> + * <b><u>DO NOT CHANGE THIS ORDER!</u></b> + * + * @param {String} pUser <p> + * To check. + * @return <p> + * Effective calendar id.<br> + */ +CalendarUtil.getEffectiveCalendarIdFromUser = function(pUser) +{ + var userParams = pUser["params"]; + + var resolvedCurrentUser; + var exchangeEmail = userParams["exchangeEMail"]; + var calendarId = userParams["calendarID"]; + var email = userParams["email"]; + + if(exchangeEmail) + return exchangeEmail; + else if(calendarId) + return calendarId; + else if(email) + return email; + else + return ""; +} + + +/* + * Creates and opens an new appointment object (with link). + * + * @param {String} pSummary (optional) <p> + * The summary.<br> + * @param {String} pDescription (optional) <p> + * The description.<br> + * @param {Boolean} pWithLink (optional) <p> + * True sets an link to $image.frametable<br> + * @param {String[][]} pWithLink (optional) Description:<br> + * <ul> + * <li>pWithLink[0]: Name of the frame</li> + * <li>pWithLink[1]: Id of the shown record</li> + * <li>pWithLink[2]: linking title</li> + * </ul> + * @param {String} pUser (optional) <p> + * The user (login). + * @param {[]} pAffectedUsers (optional) <p> + * The affected users (login). + * @param {Date} pStart (optional) <p> + * Begin of the task.<br> + * @param {Date} pDuration (optional) <p> + * Duration.<br> + * @param {Number} pCategory (optional) <p> + * calendars.CATEGORIES , encoded(String) (z.B.: text.encodeMS(["Service"])).<br> + * @param {String} pStatus (optional) <p> + * Status of the appointment:<br> + * <ul> + * <li>calendars.STATUS_TENTATIVE</li> + * <li>calendars.STATUS_CONFIRMED</li> + * <li>calendars.STATUS_CANCELLED</li> + * </ul> + * @param {Array{[]} pComps4Refresh (optional) <p> + * The component which will be updated.<br> + * @param {Array{[]} pWorklistId (optional) <p> + * The worklist id.<br> + * + * @return {void} + */ +CalendarUtil.newEvent = function( pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus, pComps4Refresh, pWorklistId) +{ + var event = CalendarUtil.createEntry( calendars.VEVENT, pSummary, pDescription, pWithLink, pUser, pAffectedUsers, pStart, pDuration, pCategory, pStatus ); + + var prompts = []; + prompts["comp4refresh"] = []; + if (pComps4Refresh == undefined) + pComps4Refresh = ["$comp.Aufgabe", "$comp.tbl_Termine"]; + for (let i = 0; i < pComps4Refresh.length; i++) + { + if ( vars.exists(pComps4Refresh[i])) prompts["comp4refresh"].push(pComps4Refresh[i]); + } + + if(vars.getString("$sys.scope") == "vaadin") + neon.openCalendarEntry([event],"", neon.OPERATINGSTATE_NEW, null) + else + { + prompts["window"] = vars.getString("$sys.currentwindow"); + prompts["image"] = vars.getString("$sys.currentimage"); + if (pWorklistId != undefined) + prompts["worklistId"] = pWorklistId; + swing.openCalendarEntry([event], null, false, prompts); + } +} + + +/* + * Creates an new appointment entry. + * + * @param {String} pSummary (optional) <p> + * The summary/title of the appointment. + * @param {String} pDescription (optional) <p> + * The appointment description. + * @param {String} pLinks (optional) <p> + * The links as objects <u>(key: "OBJECT_ID" & "OBJECT_TYPE")</u> in an array. + * @param {String} pOwner (optional) <p> + * The calendar-user (username) which will be specified as entry-owner. + * @param {String[]} pAffectedUsers (optional) <p> + * The affected users (username). + * @param {Date} pStart (optional) <p> + * The start of the appointment. + * @param {Date} pEnd (optional) <p> + * The end of the appointment. + * @param {String[]} pCategories (optional) <p> + * The categories of the appointment, the default ones are:<br> + * <ul> + * <li>Meeting</li> + * <li>Organisation</li> + * <li>OutOfOffice</li> + * <li>Vacation</li> + * </ul> + * @param {String} pStatus (optional) <p> + * Status of the appointment:<br> + * <ul> + * <li>calendars.STATUS_TENTATIVE</li> + * <li>calendars.STATUS_CONFIRMED</li> + * <li>calendars.STATUS_CANCELLED</li> + * </ul> + * @param {Date} pReminder (optional) <p> + * Date of the reminder for the appointment. + * @param {String[]} pExternalAttendees (optional) <p> + * External attendees. + * @param {String} pLocation (optional) <p> + * The location of the appointment. + * @param {Boolean} pIsAllDay (optional) <p> + * Whether if it is an all-day appointment or not. + * @param {String} pClassification (optional) <p> + * The classification of the appointment:<br> + * <ul> + * <li>calendars.CLASSIFICATION_PUBLIC</li> + * <li>calendars.CLASSIFICATION_PRIVATE</li> + * </ul> + * @return {void} + */ +CalendarUtil.newSilentEvent = function(pSummary, pDescription, pLinks, pOwner, pAffectedUsers, pStart, pEnd, pCategories, pStatus, + pReminder, pExternalAttendees, pLocation, pIsAllDay, pClassification) +{ + var event = CalendarUtil.createEntry(pSummary, pDescription, pLinks, pOwner, pAffectedUsers, pStart, pEnd, pCategories, pStatus, pReminder, + pExternalAttendees, pLocation, pIsAllDay, pClassification); + + var ids = calendars.insert([event], calendars.GROUP_SINGLE); + + if(pLinks) + { + var conf; + + pLinks.forEach(function(pLink){ + conf = entities.createConfigForAddingRows().entity("AppointmentLink_entity").fieldValues({ + "APPOINTMENT_ID" : ids[0], + "OBJECTID" : pLink["OBJECT_ID"], + "OBJECTTYPE" : pLink["OBJECT_TYPE"] + }); + + entities.createRow(conf); + }); + } +} + +/* + * Creates an new appointment object, which is responsible for holding the data<br> + * till it's used to insert with: calendars.insert (e.g.: in Appointment_entity). + * + * @param {String} pSummary (optional) <p> + * The summary/title of the appointment. + * @param {String} pDescription (optional) <p> + * The description of the appointment. + * @param {Object[]} pLinks (optional) <p> + * The links as objects <u>(key: "OBJECT_ID" & "OBJECT_TYPE")</u> in an array. + * @param {String} pOwner (optional) <p> + * The calendar-user (username) which will be specified as entry-owner. + * @param {String[]} pAffectedUsers (optional) <p> + * The affected users (usernames), which will be added to the appointment. + * @param {Date} pStart (optional) <p> + * Start of the appointment. + * @param {Date} pEnd (optional) <p> + * Duration of the appointment. + * @param {String[]} pCategories (optional) <p> + * The categories of the appointment, the default ones are:<br> + * <ul> + * <li>Meeting</li> + * <li>Organisation</li> + * <li>OutOfOffice</li> + * <li>Vacation</li> + * </ul> + * @param {String} pStatus (optional) Status of the appointment:<br> + * <ul> + * <li>calendars.STATUS_TENTATIVE</li> + * <li>calendars.STATUS_CONFIRMED</li> + * <li>calendars.STATUS_CANCELLED</li> + * </ul> + * @param {Date} pReminder (optional) <p> + * Date of reminder. + * @param {String[]} pExternalAttendees (optional) <p> + * External attendes (e-mail addresses). + * @param {String} pLocation (optional) <p> + * The locations of the appointment. + * @param {Boolean} pIsAllDay (optional) <p> + * Whether if it is an all-day appointment or not. + * @param {String} pClassification (optional) <p> + * The classification of the appointment: + * <ul> + * <li>calendars.CLASSIFICATION_PUBLIC</li> + * <li>calendars.CLASSIFICATION_PRIVATE</li> + * </ul> + * @return {Object} + */ +CalendarUtil.createEntry = function(pSummary, pDescription, pLinks, pOwner, pAffectedUsers, pStart, pEnd, pCategories, pStatus, + pReminder, pExternalAttendees, pLocation, pIsAllDay, pClassification) +{ + var entry = {}; + + entry[calendars.TYPE] = calendars.VEVENT; // hardcoded, cause only other option would be calendars.VTODO for an task + // since tasks are handled via. Task_entity there is no need for the calendars.VTODO option. + + if (!pDescription) + { + if(vars.getString("$sys.scope") == "vaadin") + { + pDescription = neon.getImageContent(vars.getString("$sys.currententityname")); + } + else + { + pDescription = swing.getImageContent(); //todo: check whether it's necessary or not. #1047482 + } + } + + if (!pOwner) + { + pOwner = vars.getString("$sys.user"); + } + + if (!pStart) + { + entry[calendars.DTSTART] = Date.now(); + } + else + { + entry[calendars.DTSTART] = pStart.getTime(); + } + + if (!pEnd) + { + let tempStartdate = entry[calendars.DTSTART]; + entry[calendars.DTEND] = tempStartdate + datetime.ONE_HOUR; + } + else + { + entry[calendars.DTEND] = pEnd.getTime().toString(); + } + + if (!pCategories || pCategories == []) + { + pCategories = ""; + } + else + { + for (i = 0; i < pCategories.length; i++) + { + pCategories[i] = translate.text(pCategories[i]); + } + + pCategories = text.encodeMS(pCategories); + } + + if ((pAffectedUsers == null || pAffectedUsers == undefined) && (pExternalAttendees == null || pExternalAttendees == undefined)) + { + entry[calendars.AFFECTEDUSERS] = ""; + } + else + { + var affectedUsers = []; + affectedUsers.push(calendars.getCalendarUser(vars.get("$sys.user"))); + + if(pAffectedUsers && pAffectedUsers != []) + { + affectedUsers = calendars.getCalendarUsers(pAffectedUsers); + } + + if(pExternalAttendees && pExternalAttendees != []) + { + for(let i = 0; i < pExternalAttendees.length; i++) + { + affectedUsers.push("; mailto:" + pExternalAttendees[i] + "; CN:" + pExternalAttendees[i] + "; ") + } + } + + entry[calendars.AFFECTEDUSERS] = text.encodeMS(affectedUsers); + } + + if (!pStatus) + { + pStatus = calendars.STATUS_CONFIRMED; + } + + if(pReminder) + { + entry[calendars.HASREMINDER] = "true"; + entry[calendars.REMINDER_DURATION] = pReminder.getTime().toString(); + } + else + { + entry[calendars.HASREMINDER] = "false"; + } + + if(pLinks) + { + entry["LINKS"] = pLinks; + } + + entry[calendars.USER] = calendars.getCalendarUser(pOwner); + entry[calendars.DESCRIPTION] = pDescription; + entry[calendars.SUMMARY] = pSummary || ""; + entry[calendars.STATUS] = CalendarUtil.mapCalendarStatus(pStatus, calendars.getBackendType()); + entry[calendars.CLASSIFICATION] = pClassification || calendars.CLASSIFICATION_PUBLIC; + entry[calendars.CATEGORIES] = pCategories; + entry[calendars.TRANSPARENCY] = "OPAQUE"; + entry[calendars.LOCATION] = pLocation || ""; + entry["X-ADITO-ISALLDAYEVENT"] = pIsAllDay ? "TRUE" : "FALSE"; + entry[calendars.DTSTART] = entry[calendars.DTSTART].toString(); + + return entry; +} + +/* + * Add an condition.<br> + * + * @param {[]} pConditions <p> + * The condition.<br> + * @param {Integer} pIndex <p> + * Index of the condition.<br> + * @param {Object} pValues <p> + * The values.<br> + * @return {void} + */ +CalendarUtil.addEntryCondition = function(pConditions, pIndex, pValues) +{ + var params = ["TYPE", "START", "END", "USER", "STATUS", "UID"]; + + for (var i = 0; i < params.length; i++) + if (pValues[params[i]] != undefined) pConditions[params[i] + "_" + pIndex] = pValues[params[i]]; +} + +/* + * Returns the date without the time.<br> + * + * @param {String} datetimeIn <p> + * Datetime.<br> + * @return {Date} <p> + * The desired date.<br> + */ +CalendarUtil.getDate = function(datetimeIn) +{ + if ( datetimeIn != "") + return datetime.clearTime(datetimeIn); + else return ""; +} + +/* + * Resets the event filter.<br> + * + * @return {Object} + */ +CalendarUtil.reset_filterEvent = function() +{ + var today = CalendarUtil.getDate(vars.getString("$sys.date")); + + return pFilter = { + user: vars.getString("$sys.user"), + datefrom: String(today), //nur die Termine ab heute anzeigen, + //die von vor einer Woche sind uninteressant + dateto: String(eMath.addInt(eMath.addInt(today, datetime.ONE_WEEK) + ,datetime.ONE_DAY - datetime.ONE_MINUTE)), + category: "", + tentative: "true", + confirmed: "true", + cancelled: "", + free: "true" + }; +} + +/* + * Gibt den richtigen Status zum Prüfen je nach Backend zurück + * Returns the matching status, to the corresponding backend. + * + * + * @param {String} pStatus req die konstante für den zu prüfenden status, + * z.B. calendars.STATUS_INPROCESS + * + * @param {String} pCalendarType req die konstante für den typen des Termin- oder Aufgabenbackends, + * z.B. calendars.BACKEND_DB + * + * @return {String} Konstanten für den Kalender (Backend-Typen), gibt es den status im backend nicht + * wird null geliefert + */ +CalendarUtil.mapCalendarStatus = function(pStatus, pCalendarType) +{ + switch (pCalendarType) + { + //case calendars.BACKEND_EXCHANGE: + case calendars.BACKEND_EXCHANGEWS: + if (pStatus == calendars.STATUS_CONFIRMED) + return calendars.STATUS_BUSY; + else + return pStatus; + default: + if (pStatus == calendars.STATUS_OOF)//nur bei exchange + return null; + else + return pStatus; + } +} + +/** + * Returns the "real" calendar system/backend type<br> + * (e.g.: BackendType & SyncBackendType) + * + * @param {Number} pScope <p> + * The needed scope:<br> + * <ul> + * <li>calendars.VEVENT</li> + * <li>calendars.VTODO</li> + * </ul> + * @return {Number} <p> + * The backend type (e.g.: calendars.BACKEND_*).<br> + */ +CalendarUtil.getCalendarSystemType = function(pScope) +{ + // Check sync backend type + if (calendars.getSyncBackendType() != calendars.BACKEND_NONE && calendars.getSyncBackendType() != 3) + { + var scope = calendars.getSyncBackendTypeScope(); + if (scope.length == 1 && scope[0] == pScope) // Scope.length = 1 -> VEVENT *OR* VTODO + return calendars.getSyncBackendType(); + else if (scope.length == 2) // Scope.length = 2 -> Both + return calendars.getSyncBackendType(); + // Scope.length = 0 -> Nothing selected -> Skip this block + } + + // Fallback to backend type (event) + if (calendars.getBackendType() != calendars.BACKEND_NONE && pScope === calendars.VEVENT) + return calendars.getBackendType(); + + // Second fallback to backend type (todo) + if (calendars.getBackendTypeTasks() != calendars.BACKEND_NONE && pScope === calendars.VTODO) + return calendars.getBackendTypeTasks(); + + // Everything is none + return calendars.BACKEND_NONE; +} + +CalendarUtil.buildEntriesFromUids = function(appointmentUids) +{ + var entryArray = new Array(appointmentUids.length); + + for(var i = 0; i < appointmentUids.length; i++) + { + var hasPermission = true; + + if(vars.get("$param.ErrorOnPermissionDenied") == "false" || vars.getString("$param.LinkedAppointmentsFromDashlet_param")) + hasPermission = hasUserPermissionForReadingEntry(getEntryOwnerCn(appointmentUids[i])); + + if(hasPermission) + entryArray[i] = CalendarUtil.buildEntry(calendars.getEntry(appointmentUids[i], null, null), null); + } + + //filter out all null + var filteredEntryArray = entryArray.filter(function (el) { + return el != null; + }); + + return filteredEntryArray; +} + + +CalendarUtil.countEntriesFromUids = function(appointmentUids) +{ + return CalendarUtil.buildEntriesFromUids(appointmentUids).length; +} + +CalendarUtil.buildEntry = function (pEntry, pMasterentry) +{ + var uid = pEntry[calendars.ID]; + var summary = pEntry[calendars.SUMMARY]; + var attendees = pEntry[calendars.AFFECTEDUSERS]; + var startdate = pEntry[calendars.DTSTART]; + var enddate = pEntry[calendars.DTEND]; + var links = pEntry[calendars.LINKS]; + var description = pEntry[calendars.DESCRIPTION]; + if(pEntry[calendars.ORGANIZER2] != undefined) + var organizer = pEntry[calendars.ORGANIZER2]["paramvalue"]; + if(pEntry[calendars.USER2] != undefined) + var owner = JSON.stringify(pEntry[calendars.USER2]); + var status = pEntry[calendars.STATUS]; + var location = pEntry[calendars.LOCATION]; + var reminder = pEntry[calendars.REMINDER_DURATION]; + var remindercheck = pEntry[calendars.HASREMINDER] + var classification = pEntry[calendars.CLASSIFICATION]; + var transparency = pEntry[calendars.TRANSPARENCY]; + var categories = pEntry[calendars.CATEGORIES]; + var isAllDay = pEntry["X-ADITO-ISALLDAYEVENT"] != null ? pEntry["X-ADITO-ISALLDAYEVENT"] : "FALSE"; + + var masterBegin = pMasterentry != null ? pMasterentry[calendars.DTSTART] : null + var masterEnd = pMasterentry != null ? pMasterentry[calendars.DTEND] : null + + // Recurrence + var recurrenceID = pEntry[calendars.RECURRENCEID]; + var rrule = null; + if (pMasterentry != null) { // Entry is a recurrence exception, therefore get rrule from master + rrule = pMasterentry[calendars.RRULE] != null ? pMasterentry[calendars.RRULE][0] : null; + } else { + rrule = pEntry[calendars.RRULE] != null ? pEntry[calendars.RRULE][0] : null; + } + + return [ + uid, + attendees.length, + startdate, + enddate, + summary, + organizer, + owner, + attendees, + status, + description, + location, + '', + isAllDay, + classification, + transparency, + categories, + reminder, + remindercheck, + rrule, + recurrenceID, + null, + masterBegin, + masterEnd, + null + ]; +} + + +function hasUserPermissionForReadingEntry(calUserCn) +{ + return calendars.hasPermission(calUserCn, calendars.VEVENT, "READ"); +} + +function getEntryOwnerCn(appointmentUid) +{ + + var owner = newSelect("ASYS_CALENDARBACKEND.OWNER", "_____SYSTEMALIAS") + .from("ASYS_CALENDARBACKEND") + .whereIfSet("ASYS_CALENDARBACKEND.ELEMENTUID", appointmentUid) + .cell(true); + + var ownerArr = text.decodeMS(owner); + return ownerArr[1].split(":")[1]; } \ No newline at end of file diff --git a/process/Email_lib/process.js b/process/Email_lib/process.js index 8f560c533ad7994e8b1896715b41ee6aabb311b6..61787a5d831ae07d315df9530951b04849e2b560 100644 --- a/process/Email_lib/process.js +++ b/process/Email_lib/process.js @@ -34,7 +34,8 @@ function EmailWritingUtils () {} * @param {Placeholder[]} [pAdditionalPlaceholders] additional placeholders * @return {Array} the eml document as array with [filename, base64] */ -EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId, pTemplateId, pRecipientContactId, pBindata, pAttachments, pSubject, pEmailFilename, pAdditionalPlaceholders) +EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId, pTemplateId, pRecipientContactId, pBindata, pAttachments, pSubject, + pEmailFilename, pAdditionalPlaceholders) { if (pToRecipients && typeof(pToRecipients) == "string") pToRecipients = [pToRecipients]; @@ -66,9 +67,13 @@ EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId, } if (pSubject) + { email.subject = pSubject; + } + + var isBinaryExistent = db.getBinaryCount("DOCUMENTTEMPLATE", "DOCUMENT", pTemplateId, SqlUtils.getBinariesAlias(), null); - return email.downloadEML(pEmailFilename); + return isBinaryExistent > 0 ? email.downloadEML(pEmailFilename) : []; } diff --git a/process/UnitTest_lib/process.js b/process/UnitTest_lib/process.js index 382d37e021567c924734a1350a7a368acd1796d3..210ab48b8f435e633a665feed0a9dd766630d990 100644 --- a/process/UnitTest_lib/process.js +++ b/process/UnitTest_lib/process.js @@ -261,7 +261,7 @@ Tester.prototype.equals = function(pExpect, pCustomDescription) if(Utils.isObject(this.actualValue) || Utils.isObject(this.expectedValue)) { - this.expectedDisplayValue = JSON.stringify(this.actualValue); + this.expectedDisplayValue = JSON.stringify(this.actualValue, _getCircularReplacer()); this._testResult = Utils.isEqual(this.actualValue, this.expectedValue); this._generateAssertDescription({custom: pCustomDescription, operator: "===", name: "Object value"}); } @@ -272,6 +272,24 @@ Tester.prototype.equals = function(pExpect, pCustomDescription) } return this; + + //custom replacer that supports cyclic references + function _getCircularReplacer () + { + var seen = new WeakSet(); + return function (key, value) + { + if (typeof value === "object" && value !== null) + { + if (seen.has(value)) + { + return "{...}"; + } + seen.add(value); + } + return value; + } + } } /** @@ -1202,7 +1220,7 @@ Tester.prototype._generateTestTitle = function(pTest, pDataProviderIndex) var titleValues = []; this.dataProvider[pDataProviderIndex].forEach(function(pElement) { - titleValues.push(pElement === undefined ? "undefined" : JSON.stringify(pElement)); + titleValues.push(pElement === undefined ? "undefined" : JSON.stringify(pElement, _getCircularReplacer())); }); this._log("", this.t.info("\t\u2699 Test: " + pTest.name) + this.t.debug(" (#" + (pDataProviderIndex + 1) + ": " + titleValues.join(" | ") + ")")); } @@ -1210,6 +1228,24 @@ Tester.prototype._generateTestTitle = function(pTest, pDataProviderIndex) { this._log("info", "\t\u2699 Test: " + pTest.name); } + + //custom replacer that supports cyclic references + function _getCircularReplacer () + { + var seen = new WeakSet(); + return function (key, value) + { + if (typeof value === "object" && value !== null) + { + if (seen.has(value)) + { + return "{...}"; + } + seen.add(value); + } + return value; + } + } } /** diff --git a/process/Util_lib/process.js b/process/Util_lib/process.js index 8ea572643943a2724f7a323e207122ff530957de..4ef286fe09d3ed55ed6394c8b950ed650c71c67c 100644 --- a/process/Util_lib/process.js +++ b/process/Util_lib/process.js @@ -100,7 +100,7 @@ Utils.isNotNullOrEmptyString = function (pValue) */ Utils.clone = function (pObject) { - var referenceMap = new Map(); + var referenceMap = new WeakMap(); return _clone(pObject); function _clone (pObject) @@ -173,35 +173,62 @@ Utils.clone = function (pObject) */ Utils.isEqual = function (pFirstObject, pSecondObject) { - var firstType = typeof pFirstObject; - var secondType = typeof pSecondObject; - if (firstType !== secondType) - return false; - if (firstType === "object" && pFirstObject !== null && pSecondObject !== null) //check for null because typeof null is also "object" + var comparedObjects = new WeakMap(); + return _isEqual(pFirstObject, pSecondObject); + + function _isEqual (pFirstObject, pSecondObject) { - var isFirstArray = Array.isArray(pFirstObject); - var isSecondArray = Array.isArray(pSecondObject); - if (isFirstArray !== isSecondArray) //return false if only one object is an array - return false; - if (isFirstArray && pFirstObject.length !== pSecondObject.length) + var firstType = typeof pFirstObject; + var secondType = typeof pSecondObject; + if (firstType !== secondType) + { return false; - - for (let key in pSecondObject) + } + if (firstType === "object" && pFirstObject !== null && pSecondObject !== null) //check for null because typeof null is also "object" { - if (!(key in pFirstObject)) + //All object comparisons are saved in comparedObjects, this makes it possible to detect recursions. + //If two objects have been checked for equality already, it can be safely assumed they are equal, + //because if they weren't, this function would have returned false already + if (comparedObjects.get(pFirstObject) === pSecondObject) + { + return true; + } + comparedObjects.set(pFirstObject, pSecondObject); + + var isFirstArray = Array.isArray(pFirstObject); + var isSecondArray = Array.isArray(pSecondObject); + if (isFirstArray !== isSecondArray) //return false if only one object is an array + { + return false; + } + if (isFirstArray && pFirstObject.length !== pSecondObject.length) + { return false; + } + + for (let key in pSecondObject) + { + if (!(key in pFirstObject)) + { + return false; + } + } + for (let key in pFirstObject) + { + if (!(key in pSecondObject) || !_isEqual(pFirstObject[key], pSecondObject[key])) + { + return false; + } + } + return true; } - for (let key in pFirstObject) + if (firstType === "number" && Number.isNaN(pFirstObject) && Number.isNaN(pSecondObject)) //NaN should be equal to NaN { - if (!(key in pSecondObject) || !Utils.isEqual(pFirstObject[key], pSecondObject[key])) - return false; + return true; } - return true; + + return pFirstObject === pSecondObject; } - if (firstType === "number" && Number.isNaN(pFirstObject) && Number.isNaN(pSecondObject)) //NaN should be equal to NaN - return true; - - return pFirstObject === pSecondObject; } /** diff --git a/process/Utils_test/Utils_test.aod b/process/Utils_test/Utils_test.aod new file mode 100644 index 0000000000000000000000000000000000000000..f877069734b9b8465243129b62e612e9f887887a --- /dev/null +++ b/process/Utils_test/Utils_test.aod @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.2"> + <name>Utils_test</name> + <title>[TEST] Util_lib</title> + <majorModelMode>DISTRIBUTED</majorModelMode> + <icon>VAADIN:CHECK_CIRCLE</icon> + <process>%aditoprj%/process/Utils_test/process.js</process> + <variants> + <element>EXECUTABLE</element> + </variants> +</process> diff --git a/process/Utils_test/process.js b/process/Utils_test/process.js new file mode 100644 index 0000000000000000000000000000000000000000..3a094ad4dcb4e17784be072b5c6089ac636b2d8a --- /dev/null +++ b/process/Utils_test/process.js @@ -0,0 +1,542 @@ +import("Util_lib"); +import("system.result"); +import("system.vars"); +import("UnitTest_lib"); + +var isEmpty = new TestSuite("Utils.isEmpty", [ + new Test("should test if an object, string or array is empty", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isEmpty(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [true, ""], + [true, []], + [true, {}], + [true, new Set()], + [true, new Map()], + [true, function () {}], + [false, "never gonna"], + [false, ["give"]], + [false, {you: "up"}], + [false, new Set(["never gonna"])], + [false, new Map([["let", "you down"]])] + ]; + } + ) +]); + +var isNullOrEmpty = new TestSuite("Utils.isNullOrEmpty", [ + new Test("should test if value is null, undefined or empty", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isNullOrEmpty(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [true, null], + [true, undefined], + [true, ""], + [true, []], + [true, {}], + [true, new Set()], + [true, new Map()], + [true, function () {}], + [false, "never gonna"], + [false, ["give"]], + [false, {you: "up"}], + [false, new Set(["never gonna"])], + [false, new Map([["let", "you down"]])] + ]; + } + ) +]); + +var isNullOrEmptyString = new TestSuite("Utils.isNullOrEmptyString", [ + new Test("should test if value is null, undefined or empty string", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isNullOrEmptyString(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [true, null], + [true, undefined], + [true, ""], + [false, 0], + [false, 42], + [false, false], + [false, true], + [false, []], + [false, {}], + [false, new Set()], + [false, new Map()], + [false, function () {}], + [false, "never gonna"], + [false, ["give"]], + [false, {you: "up"}], + [false, new Set(["never gonna"])], + [false, new Map([["let", "you down"]])] + ]; + } + ) +]); + +var isNotNullOrEmptyString = new TestSuite("Utils.isNotNullOrEmptyString", [ + new Test("should test if value isn't null, undefined or empty string", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isNotNullOrEmptyString(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, ""], + [true, 0], + [true, 42], + [true, false], + [true, true], + [true, []], + [true, {}], + [true, new Set()], + [true, new Map()], + [true, function () {}], + [true, "never gonna"], + [true, ["give"]], + [true, {you: "up"}], + [true, new Set(["never gonna"])], + [true, new Map([["let", "you down"]])] + ]; + } + ) +]); + +var clone = new TestSuite("Utils.clone", [ + new Test("should test if value is copied correctly", + function (pTester, pDataProvider) + { + var original = pDataProvider[0]; + var copy = Utils.clone(original); + + pTester.expectThat(original).equals(copy).assert(); + }, + function dataProvider() + { + var recursiveObj = {test: "Test"}; + recursiveObj.recursion = recursiveObj; + return [ + [null], + [undefined], + [0], + [42], + [""], + ["yeee"], + [[]], + [{}], + [["one", "two", 3, 4]], + [{one: "two", three: 4}], + [["one", "two", [3, 4, {five: "6"}]]], + [{one: "two", three: [4, {five: "6"}]}], + [new Set(["one", "two", 3, 4])], + [new Map([["one", "two"], [3, 4]])], + [recursiveObj] + ]; + } + ) +]); + +var isEqual = new TestSuite("Utils.isEqual", [ + new Test("should test if object equality is checked correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isEqual(pDataProvider[1], pDataProvider[2]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + var num = 0; + var str = "0"; + var objStr = new String("0"); + var obj_1 = {a: 1, b: 2, c: 3}; + var obj_2 = {x: null, y: "test", z: true}; + var recursiveObj1 = {test: "Test"}; + recursiveObj1.recursion = recursiveObj1; + var recursiveObj2 = {test: "Test"}; + recursiveObj2.recursion = recursiveObj2; + + return [ + [true, num, num], + [true, str, str], + [true, true, true], + [true, objStr, objStr], + [true, obj_1, obj_1], + [true, obj_2, obj_2], + [false, true, false], + [false, obj_1, obj_2], + [false, num, objStr], + [false, num, str], + [false, objStr, str], + [false, null, undefined], + [false, objStr, null], + [false, objStr, undefined], + [false, null, "null"], + [true, recursiveObj1, recursiveObj2] + ]; + } + ) +]); + +var isFunction = new TestSuite("Utils.isFunction", [ + new Test("should test if functions are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isFunction(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [true, function () {}], + [true, (function () {}).bind({})], + [false, null], + [false, undefined], + [false, true], + [false, false], + [false, 0], + [false, "str"], + [false, {}], + [false, []], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isString = new TestSuite("Utils.isString", [ + new Test("should test if strings are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isString(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [false, 0], + [true, ""], + [true, "str"], + [false, new String("")], + [false, {}], + [false, []], + [false, function () {}], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isNumber = new TestSuite("Utils.isNumber", [ + new Test("should test if numbers are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isNumber(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [true, 0], + [true, NaN], + [true, Infinity], + [false, "0"], + [false, {}], + [false, []], + [false, function () {}], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isNumeric = new TestSuite("Utils.isNumeric", [ + new Test("should test if numbers are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isNumeric(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [true, 0], + [true, "0"], + [false, "notnumber"], + [false, {}], + [false, []], + [false, function () {}], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isInteger = new TestSuite("Utils.isInteger", [ + new Test("should test if integers are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isInteger(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [true, 0], + [true, "0"], + [true, 1.0], + [true, "1.0"], + [false, 1.2], + [false, "1.2"], + [false, NaN], + [false, Infinity], + [false, "notnumber"], + [false, {}], + [false, []], + [false, function () {}], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isFloat = new TestSuite("Utils.isFloat", [ + new Test("should test if floats are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isFloat(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [false, 0], + [false, "0"], + [false, 1.0], + [false, "1.0"], + [true, 1.2], + [true, "1.2"], + [false, NaN], + [false, Infinity], + [false, "notnumber"], + [false, {}], + [false, []], + [false, function () {}], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isObject = new TestSuite("Utils.isObject", [ + new Test("should test if objects are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isObject(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [false, 0], + [false, "0"], + [false, NaN], + [false, Infinity], + [true, {}], + [true, []], + [false, function () {}], + [true, new Map()], + [true, new Set()] + ]; + } + ) +]); + +var isMap = new TestSuite("Utils.isMap", [ + new Test("should test if maps are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isMap(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [false, true], + [false, false], + [false, 0], + [false, "0"], + [false, NaN], + [false, Infinity], + [false, {}], + [false, []], + [false, function () {}], + [true, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var isBoolean = new TestSuite("Utils.isBoolean", [ + new Test("should test if booleans are identified correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.isBoolean(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [false, null], + [false, undefined], + [true, true], + [true, false], + [false, 0], + [false, "0"], + [false, NaN], + [false, Infinity], + [false, {}], + [false, []], + [false, function () {}], + [false, new Map()], + [false, new Set()] + ]; + } + ) +]); + +var toBoolean = new TestSuite("Utils.toBoolean", [ + new Test("should test if boolean-ish values are parsed correctly", + function (pTester, pDataProvider) + { + var expectValue = pDataProvider[0]; + var actualValue = Utils.toBoolean(pDataProvider[1]); + + pTester.expectThat(actualValue).equals(expectValue).assert(); + }, + function dataProvider() + { + return [ + [true, true], + [true, 1], + [true, "1"], + [true, "true"], + [true, {}], + [true, []], + [true, function () {}], + [true, new Map()], + [true, new Set()], + [false, false], + [false, 0], + [false, "0"], + [false, ""], + [false, "false"], + [false, null], + [false, "null"], + [false, undefined], + [false, "undefined"] + ]; + } + ) +]); + +var tester = new Tester("Test Util_lib"); +tester.initCoverage(Utils); +tester.test(isEmpty); +tester.test(isNullOrEmpty); +tester.test(isNullOrEmptyString); +tester.test(clone); +tester.test(isEqual); +tester.test(isFunction); +tester.test(isString); +tester.test(isNumber); +tester.test(isNumeric); +tester.test(isInteger); +tester.test(isFloat); +tester.test(isObject); +tester.test(isMap); +tester.test(isBoolean); +tester.test(toBoolean); + +tester.summary(); + +result.object(tester.getResults());