3175 lines
120 KiB
PHP
3175 lines
120 KiB
PHP
<% /*
|
||
$Revision$
|
||
$Id$
|
||
|
||
File: shared.inc
|
||
Description: Generieke functies die door elke pagina gebruikt worden.
|
||
Parameters:
|
||
Context: Vanuit ELK asp bestand
|
||
Note: Dus gebruik met mate
|
||
|
||
*/ %>
|
||
<%
|
||
function CreateFullPath(sPath)
|
||
{
|
||
if (!fso.FolderExists(sPath))
|
||
{
|
||
while (!fso.FolderExists(sPath))
|
||
{
|
||
var sParent = sPath;
|
||
while (sParent && !fso.FolderExists(sParent))
|
||
{
|
||
var sChild = sParent;
|
||
var sParent = fso.GetParentFolderName(sChild);
|
||
}
|
||
if (!sParent)
|
||
{
|
||
__DoLog("Cannot create folder {0}, parentfolder does not exist.".format(sPath), "#f00");
|
||
INTERN_ERROR_BAD_PATH;
|
||
}
|
||
oFolder = fso.CreateFolder(sChild);
|
||
}
|
||
}
|
||
}
|
||
|
||
function hasColumn(tableview, columname, datatype)
|
||
{
|
||
var hascol = null;
|
||
var sql = "SELECT data_type FROM user_tab_cols"
|
||
+ " WHERE table_name = " + safe.quoted_sql_upper(tableview)
|
||
+ " AND column_name = " + safe.quoted_sql_upper(columname);
|
||
if (datatype)
|
||
sql += " AND data_type = " + safe.quoted_sql_upper(datatype);
|
||
var oRs = Oracle.Execute(sql);
|
||
if (!oRs.Eof)
|
||
hascol = oRs("data_type").Value;
|
||
oRs.close();
|
||
return hascol;
|
||
}
|
||
|
||
function setWebconfig(folder)
|
||
{
|
||
if (fso.FolderExists(folder) && !fso.FileExists(folder + "/web.config"))
|
||
fso.CopyFile(Server.MapPath(rooturl + '/utils/') + "/web.config", folder + "/web.config", false); // Don't overwrite
|
||
}
|
||
|
||
// Check if there are any certificates/secrets expiring within 30days
|
||
function outlookCertificateCheck() {
|
||
if (!(S("msgraph_sync_level") > 0)) {
|
||
return; // N/A
|
||
}
|
||
// Initialize hook
|
||
var hook = hookfunc.gethook("utils/exchange/res_to_graph.wsc");
|
||
var DEZE = this;
|
||
try {
|
||
var init = hook.initialize({
|
||
DEZE: DEZE,
|
||
custabspath: Server.MapPath(custpath)
|
||
});
|
||
if (init === null) { // Is alleen null als de exchange.config ontbreekt
|
||
throw new Error("File not found");
|
||
}
|
||
hook.checkExpiringAuth();
|
||
} catch (e) {
|
||
var txt = "Error in outlookCertificateCheck():\n" + e.description;
|
||
// Note: @prod krijgen we 'Class not registered' in plaats van 'Path not found' maar de oorzaak is hetzelfde
|
||
if (e.description === "File not found" || e.description === "Path not found" || e.description.match(/^Class not registered/)) {
|
||
txt += "\nWaarschijnlijk ontbreekt de exchange.config";
|
||
}
|
||
__DoLog(txt, "#FF0000");
|
||
}
|
||
hook = null;
|
||
}
|
||
|
||
// In deze functie komen we in ieder geval <20><>n keer per dag ('s ochtends als de application pool opstart)
|
||
// Doe allerlei housekeeping hier.
|
||
// Let op dat niet bekend is welke user toevallig de eerste van de dag is. Daarom onafhankelijk van autorisatie
|
||
// Let op dat het wordt aangeroepen vanuit default.inc/loadSET() dus ook iedere keer als een setting wijzigt!
|
||
function fclt_register_task()
|
||
{
|
||
if (S("tsk_master_schema"))
|
||
{
|
||
var sql = "BEGIN"
|
||
+ " tsk.registercust();"
|
||
+ " tsk.registertask('PUTORDERS');"
|
||
+ "END;"
|
||
var err = Oracle.Execute(sql, true);
|
||
if (err.friendlyMsg)
|
||
{
|
||
// Bijzonder fataal omdat de fac_tracking trigger fac_notifytracking aanroept die ook niet bij de tasker kan
|
||
var orauser = Oracle.Execute("SELECT USER FROM DUAL")(0).Value;
|
||
var msg = "Unable to call tasker in Oracle schema {0}".format(S("tsk_master_schema"))
|
||
+ "\nMake sure schema {0} exists and has done a GRANT EXECUTE ON tsk TO {1}".format(S("tsk_master_schema"), orauser)
|
||
+ "\nOr: clear Facilitor setting 'tsk_master_schema'"
|
||
+ "\n\n" + err.friendlyMsg
|
||
_AiAi(msg);
|
||
}
|
||
|
||
if (S("msgraph_sync_level") & 1) { // We zijn subscribed op Exchange hooks > de tasker handelt die af
|
||
var sql = "BEGIN"
|
||
+ " tsk.registertask('EXCHANGE');"
|
||
+ "END;"
|
||
Oracle.Execute(sql); // Expliciete foutafhandeling zoals hierboven is voor deze specifieke tasker niet nodig
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// In deze functie komen we in ieder geval <20><>n keer per dag ('s ochtends als de application pool opstart)
|
||
// Doe allerlei housekeeping hier.
|
||
// Let op dat niet bekend is welke user toevallig de eerste van de dag is. Daarom onafhankelijk van autorisatie
|
||
// Let op dat het wordt aangeroepen vanuit default.inc/loadSET() dus ook iedere keer als een setting wijzigt!
|
||
function fclt_daily()
|
||
{
|
||
FCLTHeader.generateTemplateCss(); // Recreate at least once per day
|
||
setWebconfig(Server.MapPath(rooturl + '/temp/')); // geldt voor alle klanten tegelijk
|
||
// Het liefst zou ik gewoon de *hele* custfolder beschermen maar er staan wel eens
|
||
// (menu)image bestanden die via http worden benaderd.
|
||
setWebconfig(Server.MapPath(custpath + "/Export"));
|
||
setWebconfig(Server.MapPath(custpath + "/Exchange"));
|
||
setWebconfig(Server.MapPath(custpath + "/Import"));
|
||
setWebconfig(Server.MapPath(custpath + "/Plugins"));
|
||
setWebconfig(Server.MapPath(custpath + "/Tasks"));
|
||
setWebconfig(Server.MapPath(custpath + "/Xsl"));
|
||
|
||
// Pseudo overschrijding om aantal gebruikers gisteren te registreren
|
||
var sql = "BEGIN fac.fac_perfmon_incr("+S("perfmon_threshold")+", 0); END;"
|
||
Oracle.Execute(sql);
|
||
|
||
// Rotate logfile
|
||
rotateLogfile(S("max_logfile_size"));
|
||
|
||
// Controleer of certificaten en/of secrets tbv de Outlook-koppeling binnen 30 dagen verlopen
|
||
outlookCertificateCheck();
|
||
|
||
// Meestal is de fac_cleanup al minder dan 24 uur geleden door gen_scheduler/fac_daily uitgevoerd.
|
||
// Voor klanten waar geen gen_scheduler draait dan hier alsnog de cleanup.
|
||
var cleanup_sql = "BEGIN fac.fac_cleanup(); END;";
|
||
Oracle.Execute(cleanup_sql);
|
||
}
|
||
|
||
var shared = {
|
||
trackaction: // returnvalue: de nieuwe fac_tracking_key
|
||
function (paction, pkey, poms, psubjectkey, passystem) /* paction is something like 'BEZMUT', 'MLDAFM' etc */
|
||
{
|
||
var v_trackuser = (user_key>0 ? user_key : "NULL");
|
||
if (passystem)
|
||
v_trackuser = "NULL"; // forceer gebruiker "_SYSTEEM" voor automatisch gegenereerde tracking
|
||
// trackaction genereert ook eventuele notificaties
|
||
// hebben we wel of geen key voor het lijdend voorwerp van deze tracking
|
||
if (psubjectkey)
|
||
var sql = "BEGIN fac.trackaction_withkey(" + safe.quoted_sql(paction) + ", "
|
||
+ (pkey>0?pkey:"NULL") + ", "
|
||
+ v_trackuser + ", NULL, "
|
||
+ safe.quoted_sql(poms, 2000)
|
||
+ ", " + psubjectkey
|
||
+ " , new_fac_tracking_key => ?"
|
||
+ ");"
|
||
+ " END;";
|
||
else
|
||
var sql = "BEGIN fac.trackaction(" + safe.quoted_sql(paction) + ", "
|
||
+ (pkey>0?pkey:"NULL") + ", "
|
||
+ v_trackuser + ", NULL, "
|
||
+ safe.quoted_sql(poms, 2000)
|
||
+ " , new_fac_tracking_key => ?"
|
||
+ ");"
|
||
+ " END;";
|
||
var oparams = [ { typ: adInteger, dir: adParamOutput } ]; // moet op volgorde van de '?'
|
||
Oracle.ExecuteParam(sql, oparams);
|
||
var new_fac_tracking_key = oparams[0].val;
|
||
return new_fac_tracking_key;
|
||
},
|
||
|
||
notificatie_fail_BLOCK:
|
||
function (refkey, xmlnode)
|
||
{
|
||
var sql = "SELECT fac_notificatie_key,"
|
||
+ " fac_notificatie_failcount,"
|
||
+ " fac_notificatie_notbefore"
|
||
+ " FROM fac_notificatie q, "
|
||
+ " fac_srtnotificatie sn"
|
||
+ " WHERE q.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
|
||
+ " AND (q.fac_notificatie_systeemadres IS NOT NULL OR "
|
||
+ " q.prs_bedrijfadres_key IS NOT NULL)"
|
||
+ " AND q.fac_notificatie_failcount > 0" // Er kan er hooguit eentje aan het falen zijn, de rest is dan uitgesteld
|
||
+ " AND sn.fac_srtnotificatie_xmlnode = " + safe.quoted_sql(xmlnode)
|
||
+ " AND q.fac_notificatie_refkey = " + refkey
|
||
+ " ORDER BY fac_notificatie_datum, "
|
||
+ " fac_notificatie_key"
|
||
var oRs = Oracle.Execute(sql);
|
||
if (!oRs.EOF)
|
||
{
|
||
var failcount = oRs("fac_notificatie_failcount").Value;
|
||
var notbefore = new Date(oRs("fac_notificatie_notbefore").Value);
|
||
if (failcount)
|
||
{
|
||
safebody = L("lcl_noti_failsendsystem").format(failcount, toDateTimeString(notbefore));
|
||
if (user.has("WEB_PRSSYS"))
|
||
{
|
||
var onclick = "notificatie_remove(" + oRs("fac_notificatie_key").Value + ")";
|
||
var deletebutton = "<span title='{0}' style='cursor:pointer;' ".format(L("lcl_noti_delete"))
|
||
+ " onclick='{0}'>".format(safe.htmlattr(onclick))
|
||
+ " " + I("fa-trash-alt") + "</span>";
|
||
safebody = safebody + deletebutton;
|
||
}
|
||
}
|
||
SIMPLE_BLOCK_START();
|
||
Response.Write("<div class='notificatiefailer'>" + safebody + "</div>");
|
||
SIMPLE_BLOCK_END();
|
||
}
|
||
oRs.Close();
|
||
},
|
||
|
||
auditfail:
|
||
function (poms)
|
||
{
|
||
var sql = "INSERT INTO fac_auditfail (fac_auditfail_tekst) VALUES (" + safe.quoted_sql(poms, 2000) + ")";
|
||
Oracle.Execute(sql);
|
||
},
|
||
|
||
// Keep track of GUI actions, params.daily summarizes per day and/or anonymously
|
||
// 0=as-is, 1=per user per day(for personal favorites), 2=anonymous per day
|
||
registeraction:
|
||
function (pgroup, params)
|
||
{
|
||
params = params || {};
|
||
var counter_key = -1;
|
||
params.daily = params.daily||0;
|
||
params.count = params.manualCount || 1;
|
||
|
||
var flds = [];
|
||
var safevals = [];
|
||
flds.push("fac_gui_counter_group");
|
||
safevals.push(safe.quoted_sql(pgroup));
|
||
if (params.daily == -1 || params.daily == 0 || params.daily == 1)
|
||
{
|
||
flds.push("prs_perslid_key");
|
||
safevals.push(user_key);
|
||
}
|
||
if (params.truncdate || params.daily == 1 || params.daily == 2)
|
||
{
|
||
flds.push("fac_gui_counter_date");
|
||
safevals.push("TRUNC(SYSDATE)");
|
||
}
|
||
if (params.info)
|
||
{
|
||
flds.push("fac_gui_counter_info");
|
||
safevals.push(safe.quoted_sql(params.info, 1000));
|
||
}
|
||
if (params.refkey)
|
||
{
|
||
flds.push("fac_gui_counter_refkey");
|
||
safevals.push(params.refkey);
|
||
}
|
||
if (params.daily == 0)
|
||
{
|
||
var sql = "SELECT faq_s_fac_gui_counter_key.nextval FROM dual";
|
||
var oRs = Oracle.Execute( sql );
|
||
counter_key = oRs(0).value;
|
||
oRs.Close();
|
||
flds.push("fac_gui_counter_key");
|
||
safevals.push(counter_key);
|
||
|
||
sql = "BEGIN"
|
||
+ " INSERT INTO fac_gui_counter ("+flds.join(", ") + ", fac_gui_counter_count)"
|
||
+ " VALUES ("+safevals.join(", ")+", " + params.count + ");"
|
||
+ " EXCEPTION WHEN dup_val_on_index" // Twee keer in dezelfde seconde negeren
|
||
+ " THEN "
|
||
+ " NULL; "
|
||
+ " END;"
|
||
Oracle.Execute(sql);
|
||
}
|
||
else
|
||
{
|
||
// upsert the daily counter, relies on the unique index
|
||
// you might think that update-insert is more efficient (because more often) than insert-update
|
||
// JGL: inderdaad, dat is efficienter dus omgedraaid.
|
||
var wheres = [];
|
||
for (var i=0; i<flds.length; i++) {
|
||
wheres.push(flds[i] + "=" + safevals[i]);
|
||
}
|
||
var sql = "BEGIN"
|
||
+ " UPDATE fac_gui_counter SET fac_gui_counter_count = fac_gui_counter_count + " + params.count
|
||
+ (params.daily === -1 ? " , fac_gui_counter_date = SYSDATE" : "")
|
||
+ " WHERE (" + wheres.join(" AND ") + ");"
|
||
+ " IF SQL%ROWCOUNT = 0 THEN"
|
||
+ " INSERT INTO fac_gui_counter (" + flds.join(", ") + ", fac_gui_counter_count)"
|
||
+ " SELECT " + safevals.join(", ") + ", " + params.count
|
||
+ " FROM DUAL"
|
||
+ " WHERE NOT EXISTS (SELECT fac_gui_counter_key" // Multi-user safe maken (FCLT#77015).
|
||
+ " FROM fac_gui_counter"
|
||
+ " WHERE (" + wheres.join(" AND ") + "));"
|
||
+ " END IF;"
|
||
+ " END;";
|
||
Oracle.Execute(sql);
|
||
}
|
||
return counter_key;
|
||
},
|
||
|
||
// Verondersteld dat head al is geweest.
|
||
simpel_body: function(bodyhtml)
|
||
{
|
||
Response.Write("<body class='simpelpage'>");
|
||
Response.Write(bodyhtml);
|
||
Response.Write("</body></html>");
|
||
Response.End;
|
||
},
|
||
|
||
// Maak een heel simpele pagina.
|
||
// Als DOCTYPE_Disable dan veronderstellen we een JSON-vraag en sturen we JSON terug
|
||
// (Anders zou er waarschijnlijk een Ajax Error optreden)
|
||
simpel_page: function(bodyhtml, headhtml)
|
||
{
|
||
function _httpAcceptOnly(httpAccept, type)
|
||
{
|
||
var httpAccept_arr = httpAccept.split(",");
|
||
for (var i in httpAccept_arr)
|
||
{
|
||
if (httpAccept_arr[i].indexOf("/") == -1 || httpAccept_arr[i].split("/")[1].indexOf(type) != 0)
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
var httpAccept = String(Request.ServerVariables("HTTP_ACCEPT")).split(";")[0].toLowerCase();
|
||
if (typeof mobile == "object" && "simpel_page" in mobile && _httpAcceptOnly(httpAccept, "json") == false)
|
||
mobile.simpel_page(bodyhtml);
|
||
else
|
||
if ((typeof DOCTYPE_Disable != "undefined" && JSON_Result) || _httpAcceptOnly(httpAccept, "json"))
|
||
{ // JSON
|
||
bodyhtml = bodyhtml.replace(/\<br\>/ig, "\n")
|
||
.replace(/\<p\>/ig, "\n")
|
||
.replace(/\<\/p\>$/ig, "")
|
||
.replace(/\<\/p\>/ig, "\n");
|
||
Response.Clear();
|
||
Response.Write(JSON.stringify({success: false, message: bodyhtml}));
|
||
Response.End;
|
||
}
|
||
else if (_httpAcceptOnly(httpAccept, "xml"))
|
||
{ // XML
|
||
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
|
||
xmlDoc.appendChild(xmlDoc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
|
||
|
||
var fac_elem = xmlDoc.createElement("facilitor");
|
||
var err_elem = xmlDoc.createElement("error");
|
||
var err_text = xmlDoc.createTextNode(bodyhtml);
|
||
|
||
err_elem.appendChild(err_text);
|
||
fac_elem.appendChild(err_elem);
|
||
xmlDoc.appendChild(fac_elem);
|
||
|
||
Response.ContentType = "text/xml";
|
||
Response.Clear();
|
||
Response.Write(xmlDoc.xml);
|
||
Response.End;
|
||
}
|
||
else
|
||
{ // HTML
|
||
Response.Clear();
|
||
Response.Write("<!DOCTYPE html>");
|
||
Response.Write("<html class='simpel_page'><head>");
|
||
if (typeof FCLTHeader != "undefined")
|
||
FCLTHeader.Generate();
|
||
else // Poor man styling
|
||
Response.Write("<style>* { font-family: Tahoma, Verdana; font-size: 11pt; line-height: 1.4em } </style>");
|
||
if (headhtml)
|
||
Response.Write(headhtml);
|
||
Response.Write("</head>");
|
||
shared.simpel_body(bodyhtml);
|
||
}
|
||
},
|
||
|
||
internal_error: function (message)
|
||
{
|
||
var body = L("lcl_internal_error") + " " + toISODateTimeString(new Date()) + "<p>" + safe.html(message) + "</p>";
|
||
__Log("shared.internal_error:\n" + body)
|
||
shared.simpel_page(body);
|
||
},
|
||
|
||
record_not_found: function (html)
|
||
{
|
||
shared.simpel_page(L("lcl_recnotfound_error") + (html||""));
|
||
},
|
||
|
||
// Delay in milliseconde zonder dat het processor-kracht kost
|
||
// Handig als je traag gedrag wilt simuleren
|
||
delay: function (ms)
|
||
{
|
||
var oAbout = new ActiveXObject("SLNKDWF.About");
|
||
oAbout.Sleep(ms);
|
||
},
|
||
|
||
// b64 versie levert op volgens rfc4648 zodat de waarde url-safe is
|
||
// geen +/ maar -_
|
||
// Let op: len is het aantal gewenste karakters, dat zal groter zijn dan het aantal bytes
|
||
random: function (len, encoding)
|
||
{
|
||
len = len || 32;
|
||
encoding = encoding || "base64";
|
||
switch (encoding)
|
||
{
|
||
case "base64": bytes = Math.ceil(len * 6 / 8); break;
|
||
case "base32": bytes = Math.ceil(len * 5 / 8); break;
|
||
case "hex": bytes = len * 4 / 8; break;
|
||
default: BAD_RANDOM_ENCODING;
|
||
}
|
||
try
|
||
{
|
||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
|
||
var rnd = oCrypto.hex_random(bytes);
|
||
switch (encoding)
|
||
{
|
||
case "base64": rnd = oCrypto.hex2base64(rnd, false, true); break; // no padding, urlsafe
|
||
case "base32": rnd = oCrypto.hex2base32(rnd); break;
|
||
case "hex": rnd = rnd; break;
|
||
default: BAD_RANDOM_ENCODING;
|
||
}
|
||
}
|
||
catch(e)
|
||
{ // Minstens versie 4.14 voor random
|
||
abort_with_warning("SLNKDWFx64.DLL not properly installed or too old version.\n{0}".format(e.description));
|
||
}
|
||
return rnd.substr(0, len);
|
||
},
|
||
makehash: function (str)
|
||
{
|
||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
|
||
return oCrypto.hex_sha1(str);
|
||
},
|
||
|
||
isGoodNumber: function(str, intOnly, posOnly, numLen, numDec)
|
||
{
|
||
var posOnlyStr = (posOnly ? "" : "\\-?");
|
||
var numLenStr = (numLen == -1 ? "" : (numDec == -1 ? numLen : (intOnly ? numLen : numLen - numDec)));
|
||
var numDecStr = (numDec == -1 ? "" : numDec);
|
||
|
||
var intOnlyStr = "\\d{1," + numLenStr + "}";
|
||
var dblOnlyStr = "\\d{0," + numLenStr + "}[.,]\\d{1," + numDecStr + "}" + "|"
|
||
+ "\\d{1," + numLenStr + "}[.,]\\d{0," + numDecStr + "}" ;
|
||
|
||
var anum = "^"
|
||
+ posOnlyStr + "(" + intOnlyStr
|
||
+ (intOnly ? "" : "[.,]?" + "|" + dblOnlyStr)
|
||
+ ")"
|
||
+ "$";
|
||
|
||
var patt = new RegExp(anum);
|
||
return patt.test(str);
|
||
},
|
||
|
||
// Checken of het eenheden selectveld met dagen/uren bij "Acceptatietijd" niet readonly was en wel is meegegeven.
|
||
// Als dit eenheden selectieveld readonly was dan wordt deze niet opgeslagen en dan moet de tijdsduur ook niet opgeslagen worden.
|
||
// Als 0 dagen/uren dan beide velden leeg maken. Als eenheidsveld aanwezig is, moet ook het tijdsduurveld aangwezig zijn.
|
||
add_time_field: function add_time_field(fields, dbsname, frm_tijd, frm_eenheid, track)
|
||
{
|
||
var dayshours = Request.Form(frm_eenheid).count > 0 && getFParamFloat(frm_tijd, -1) > 0;
|
||
if (dayshours)
|
||
fields.push({ dbs: dbsname + ".tijdsduur", obj: "MLD_T_UITVOERTIJD", typ: "float", frm: frm_tijd, track: (track? track.tracktijdsduur : null) },
|
||
{ dbs: dbsname + ".eenheid", obj: "MLD_T_UITVOERTIJD", typ: "varchar", frm: frm_eenheid, track: (track? track.trackeenheid : null) });
|
||
else // Leegmaken
|
||
fields.push({ dbs: dbsname + ".tijdsduur", obj: "MLD_T_UITVOERTIJD", typ: "float", val: null, track: (track? track.tracktijdsduur : null) },
|
||
{ dbs: dbsname + ".eenheid", obj: "MLD_T_UITVOERTIJD", typ: "varchar", val: null, track: (track? track.trackeenheid : null) });
|
||
return fields;
|
||
},
|
||
// Converteer zo veel mogelijk direct naar goede type
|
||
_qssafe: function __qssafe(model, fld, strval)
|
||
{
|
||
if (fld.toLowerCase() == 'id')
|
||
{
|
||
if (String(strval).toLowerCase() == "self")
|
||
return user_key;
|
||
else
|
||
return parseInt(strval, 10);
|
||
}
|
||
if (fld.toLowerCase() == 'limit')
|
||
return parseInt(strval, 10);
|
||
if (fld.toLowerCase() == 'offset')
|
||
return parseInt(strval, 10);
|
||
|
||
return strval; // NOTE: Rest nog even niet, gaf nog problemen met foreigns (FSN#33730)
|
||
// Deze moet blijven werken
|
||
// http://uwva.facws001.sg.nl/branch20211/api2/locations.json?district=~Noordwest
|
||
|
||
var field = model.fields[fld];
|
||
if (!field)
|
||
return strval;
|
||
switch (field.typ)
|
||
{
|
||
case "float":
|
||
return parseFloat(strval.replace(/,/g,"."));
|
||
break;
|
||
case "key":
|
||
case "number":
|
||
return parseInt(strval, 10);
|
||
break;
|
||
case "check":
|
||
case "check0":
|
||
//val = (Request.Form(formfields[i].frm).count==1)?1:0;
|
||
//break;
|
||
case "date":
|
||
case "datetime":
|
||
// Hier zouden we ook de ISO-dates moeten aankunnen?
|
||
//val = getFParamDate(formfields[i].frm, null);
|
||
//break;
|
||
case "memo":
|
||
case "varchar":
|
||
return strval;
|
||
break;
|
||
default:
|
||
{
|
||
return strval;
|
||
}
|
||
}
|
||
return strval;
|
||
},
|
||
form2json: function _form2json(model, transit)
|
||
{
|
||
return shared._coll2json(model, Request.Form, transit);
|
||
},
|
||
qs2json: function _qs2json(model, transit)
|
||
{
|
||
return shared._coll2json(model, Request.QueryString, transit);
|
||
},
|
||
tempFolder: function _tempFolder()
|
||
{
|
||
return Server.MapPath(rooturl + '/temp/' + customerId);
|
||
},
|
||
_coll2json: function _coll2json(model, pColl, transit) // Vergelijk ook api2.form2JSONdata die er erg op lijkt
|
||
{
|
||
var filter = {};
|
||
var scf_transit = getQParamArray("scf_transit", []);
|
||
for (var i = 1; i <= pColl.Count; i++)
|
||
{
|
||
var name = pColl.key(i).toLowerCase();
|
||
var data = pColl(i);
|
||
if (inArray(name, scf_transit) === !!transit) {
|
||
if (data.Count > 1)
|
||
{
|
||
filter[name] = [];
|
||
for (var j = 1; j <= data.Count; j ++)
|
||
filter[name].push(shared._qssafe(model, name, String(data(j))));
|
||
}
|
||
else
|
||
filter[name] = shared._qssafe(model, name, String(data));
|
||
}
|
||
}
|
||
return filter;
|
||
},
|
||
stripbbcodes: function (waarde)
|
||
{
|
||
if (!waarde || typeof waarde != "string") // early exit
|
||
return waarde;
|
||
if (waarde.indexOf("[") == -1) // snelle goedkope controle
|
||
return waarde;
|
||
|
||
var safepairs = "h1,h2,h3,h4,h5,h6,b,i,u,s,em,strong,small,big,th,td,tr,table,pre,code".split(",");
|
||
for (var i = 0; i < safepairs.length; i++)
|
||
{
|
||
var code = safepairs[i];
|
||
var strre = "\\[{0}\\]([\\S\\s]*?)\\[\\/{0}\\]".format(code); // De ? maakt de .* lazy (ipv greedy)
|
||
var strnew = "$1";
|
||
if (code == "code") // <code> heeft bij ons display: block
|
||
strnew = "\n" + strnew + "\n";
|
||
var re = new RegExp(strre, "g");
|
||
var waarde = waarde.replace(re, strnew);
|
||
}
|
||
|
||
// Checking for [color=#]
|
||
var strre = "\\[color=([#][0-9a-fA-F]{6})\\]([^\\[]*)|\\[\\/color\\]".format(code);
|
||
var strnew = "$2";
|
||
var re = new RegExp(strre, "g");
|
||
var waarde = waarde.replace(re, strnew);
|
||
|
||
// Checking for [link] url (|optionaltext) [/link]
|
||
// or [url] url (|optionaltext) [/url]
|
||
var strre = "\\[(link|url)\\]([\\S\\s]*?)\\[\\/(?:\\1)\\]";
|
||
var allowedLinkRegex = new RegExp(S("allowedLinkRegex"), "i");
|
||
var matched = waarde.match(new RegExp(strre, "gi"));
|
||
if (matched != null)
|
||
{
|
||
for (var i = 0; i < matched.length; i++)
|
||
{
|
||
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
|
||
if (groups)
|
||
{
|
||
// groups[1] = "link" of "url" (wordt verder niet gebruikt)
|
||
// groups[2] = url (|optionaltext)
|
||
var regExpResult = groups[2].split("|");
|
||
var safe_url = safe.htmlattr(regExpResult[0]);
|
||
var url_text = (regExpResult.length == 1 ? regExpResult[0] : regExpResult[1]); // (heeft geen optionaltekst ? url : optionaltext)
|
||
if (safe_url.match(allowedLinkRegex))
|
||
waarde = waarde.replace(matched[i], url_text);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Checking for [mention] prs_key | prs_name [/mention] as used in notes
|
||
strre = "\\[mention\\](\\d+)\\|(.+?)\\[\\/mention\\]";
|
||
var matched = waarde.match(new RegExp(strre, "gi"));
|
||
if (matched != null)
|
||
{
|
||
for (var i = 0; i < matched.length; i++)
|
||
{
|
||
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
|
||
if (groups)
|
||
{ // groups[1] = prs_key
|
||
// groups[2] = prs_name
|
||
waarde = waarde.replace(matched[i], "@" + groups[2]);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Checking for [img] src [/img] */
|
||
strre = "\\[img\\]([\\S\\s]*?)\\[\\/img\\]";
|
||
matched = waarde.match(new RegExp(strre, "gi"));
|
||
if (matched != null) {
|
||
for (var i = 0; i < matched.length; i++) {
|
||
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
|
||
if (groups) {
|
||
waarde = waarde.replace(matched[i], "[" + L("lcl_image") + "]");
|
||
}
|
||
}
|
||
}
|
||
return waarde;
|
||
},
|
||
mld_prefix : function (mld_key, fld) // Prefix voor meldingnummer; je kunt ook "ins_srtdiscipline_omschrijving"
|
||
{
|
||
var sql = "SELECT " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
|
||
+ " , sd.ins_srtdiscipline_prefix"
|
||
+ " FROM mld_melding m"
|
||
+ ", mld_stdmelding s"
|
||
+ ", mld_discipline md"
|
||
+ ", ins_srtdiscipline sd"
|
||
+ " WHERE mld_melding_key = " + mld_key
|
||
+ " AND s.mld_stdmelding_key = m.mld_stdmelding_key"
|
||
+ " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
|
||
+ " AND md.ins_discipline_key = s.mld_ins_discipline_key";
|
||
var oRs = Oracle.Execute(sql);
|
||
var result = oRs(fld || "ins_srtdiscipline_prefix").Value || "";
|
||
oRs.Close();
|
||
return result;
|
||
},
|
||
opdr_prefix : function (opdr_key, fld) // Prefix voor opdrachtnummer; je kunt ook "ins_srtdiscipline_omschrijving"
|
||
{
|
||
var sql = "SELECT " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
|
||
+ " , sd.ins_srtdiscipline_prefix"
|
||
+ " FROM mld_opdr mo"
|
||
+ ", mld_melding m"
|
||
+ ", mld_stdmelding s"
|
||
+ ", mld_discipline md"
|
||
+ ", ins_srtdiscipline sd"
|
||
+ " WHERE mo.mld_opdr_key = " + opdr_key
|
||
+ " AND mo.mld_melding_key = m.mld_melding_key"
|
||
+ " AND s.mld_stdmelding_key = m.mld_stdmelding_key"
|
||
+ " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
|
||
+ " AND md.ins_discipline_key = s.mld_ins_discipline_key";
|
||
var oRs = Oracle.Execute(sql);
|
||
var result = oRs(fld || "ins_srtdiscipline_prefix").Value || "";
|
||
oRs.Close();
|
||
return result;
|
||
},
|
||
/*
|
||
params: {
|
||
model: "gpt-4-turbo-preview",
|
||
instructions: "Please summarize the following message",
|
||
}
|
||
*/
|
||
promptAI: function (msg, params)
|
||
{
|
||
params = params || {};
|
||
|
||
// Tijdelijk voor 2025.3 Gold A tot 2026.1
|
||
settings.overrule_setting("ai_endpoint", "https://general-foundry-prod.cognitiveservices.azure.com/openai/deployments/general-gpt4o/chat/completions?api-version=2025-01-01-preview");
|
||
settings.overrule_setting("ai_apikey", "3XUVnWTMwxOhKEj4Jnu4hj0Ifr8B9lt0PLCdhjAVxb2krGD99wpiJQQJ99BJACfhMk5XJ3w3AAAAACOGEWSl");
|
||
|
||
var result = {};
|
||
var apikey = S("ai_apikey");
|
||
if (!apikey) {
|
||
return { error: "No API key configured" };
|
||
} else if (!msg) {
|
||
return { error: "No prompt supplied" };
|
||
}
|
||
var url = S("ai_endpoint");
|
||
|
||
var http = new ActiveXObject("MSXML2.ServerXMLHTTP.6.0");
|
||
|
||
var lResolve = 1 * 1000;
|
||
var lConnect = 1 * 1000;
|
||
var lSend = 3 * 1000;
|
||
var lReceive = 5 * 1000;
|
||
if (params.timeouts) { // Formaat = Array; [lResolve, lConnect, lSend, lReceive]
|
||
lResolve = params.timeouts[0];
|
||
lConnect = params.timeouts[1];
|
||
lSend = params.timeouts[2];
|
||
lReceive = params.timeouts[3];
|
||
}
|
||
http.setTimeouts(lResolve, lConnect, lSend, lReceive);
|
||
|
||
http.open("POST", url, false);
|
||
|
||
http.setRequestHeader("Content-Type", "application/json");
|
||
http.setRequestHeader("api-key", apikey);
|
||
|
||
var body = {
|
||
messages: [],
|
||
n: 1, // Number of completions to generate
|
||
user: customerId
|
||
}
|
||
if (params.instructions) {
|
||
body.messages.push({
|
||
role: "system",
|
||
content: params.instructions
|
||
});
|
||
}
|
||
if ("response_format" in params) {
|
||
body.response_format = { "type": params.response_format };
|
||
}
|
||
body.messages.push({
|
||
role: "user",
|
||
content: msg
|
||
});
|
||
|
||
var start = new Date().getTime();
|
||
try {
|
||
http.send(JSON.stringify(body));
|
||
/* Returns the chat completion object:
|
||
{
|
||
"id": "chatcmpl-123",
|
||
"object": "chat.completion",
|
||
"created": 1677652288,
|
||
"model": "gpt-3.5-turbo-0125",
|
||
"system_fingerprint": "fp_44709d6fcb",
|
||
"choices": [{
|
||
"index": 0,
|
||
"message": {
|
||
"role": "assistant",
|
||
"content": "\n\nHello there, how may I assist you today?",
|
||
},
|
||
"logprobs": null,
|
||
"finish_reason": "stop"
|
||
}],
|
||
"usage": {
|
||
"prompt_tokens": 9,
|
||
"completion_tokens": 12,
|
||
"total_tokens": 21
|
||
}
|
||
}
|
||
|
||
Or the error object;
|
||
{
|
||
"error": {
|
||
"message": "You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors.",
|
||
"type": "insufficient_quota",
|
||
"param": null,
|
||
"code": "insufficient_quota"
|
||
}
|
||
}
|
||
*/
|
||
if (http.status) {
|
||
if (http.status >= 200 && http.status < 300) {
|
||
var response = JSON.parse(http.responseText);
|
||
if (response.choices && response.choices.length > 0) {
|
||
result.success = true;
|
||
result.content = response.choices[0].message.content;
|
||
if (response.usage && ("total_tokens" in response.usage) && !isNaN(parseInt(response.usage.total_tokens))) {
|
||
shared.registeraction("OpenAI_req", { daily: 2 });
|
||
shared.registeraction("OpenAI_token", { daily: 2, manualCount: response.usage.total_tokens });
|
||
}
|
||
} else {
|
||
result.warning = "No response from OpenAI";
|
||
}
|
||
} else {
|
||
// Handle known errors
|
||
if (http.status == 429) {
|
||
result.warning = "Rate limit exceeded";
|
||
} else {
|
||
try {
|
||
var errorResponse = JSON.parse(http.responseText);
|
||
// De oude OpenAI error.code 'context_length_exceeded' zien we nu terug als; response.choices[0].finish_reason = "length"
|
||
result.warning = "[" + http.status + "] - OpenAI"
|
||
+ (errorResponse.error.code ? " [" + errorResponse.error.code + "]" : "")
|
||
+ " - " + errorResponse.error.message;
|
||
__DoLog(result.warning, "#FF0000");
|
||
__DoLog(body);
|
||
} catch (e) {
|
||
// Handle unknown errors
|
||
result.warning = "Error " + http.status + ": " + http.statusText;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
result.warning = "Fout bij ophalen van data";
|
||
}
|
||
} catch (e) {
|
||
result.warning = "Fout bij ophalen van data";
|
||
var duration = new Date().getTime() - start;
|
||
__DoLog("Open AI ERROR: " + e.description + " (" + duration + "ms)", "#FF0000");
|
||
}
|
||
return result;
|
||
},
|
||
readJSONfile: function (path)
|
||
{
|
||
try
|
||
{
|
||
var ff = fso.OpenTextFile(path, 1); // ForReading
|
||
var jsondata = ff.ReadAll();
|
||
ff.Close();
|
||
return JSON.parse(jsondata);
|
||
}
|
||
catch (e)
|
||
{
|
||
__DoLog(jsondata);
|
||
_AiAi("readJSONfile parse error for file {0}: {1}".format(path, e.message));
|
||
}
|
||
}
|
||
};
|
||
|
||
if (!Math.sign)
|
||
{
|
||
Math.sign = function(x)
|
||
{
|
||
// From: moz://a MDN web docs, Math.sign()
|
||
return ((x > 0) - (x < 0)) || +x;
|
||
}
|
||
}
|
||
|
||
// Check for parameter pName and return the value
|
||
// If not specified return defVal
|
||
// If defVal not specified pName a required parameter
|
||
function getQParam(pName, defVal)
|
||
{
|
||
return _get_Param(Request.Querystring, pName, defVal);
|
||
}
|
||
// Nodig binnen jQuery mobile. Gebruik tegenhanger safe.urlUTF8
|
||
function getQParamUTF8(pName, defVal)
|
||
{
|
||
return unescape(decodeURIComponent(escape(getQParam(pName, defVal))));
|
||
}
|
||
function getFParam(pName, defVal)
|
||
{
|
||
return _get_Param(Request.Form, pName, defVal);
|
||
}
|
||
function getFQParam(pName, defVal)
|
||
{
|
||
return getFParam(pName, getQParam(pName, defVal));
|
||
}
|
||
function hasQParam(pName)
|
||
{
|
||
return _has_Param(Request.Querystring, pName);
|
||
}
|
||
function hasFParam(pName)
|
||
{
|
||
return _has_Param(Request.Form, pName);
|
||
}
|
||
function _has_Param(pColl, pName)
|
||
{
|
||
return pColl(pName).Count > 0;
|
||
}
|
||
// Met force wordt een aanwezige maar lege waarde ook afgekeurd
|
||
// Met name voor (integer) key's
|
||
function _get_Param(pColl, pName, defVal, force)
|
||
{
|
||
var rq = pColl(pName);
|
||
if (rq.count > 0 && (!force || rq(1) !== ""))
|
||
return rq(1);
|
||
else
|
||
{
|
||
if (typeof defVal != 'undefined')
|
||
return defVal;
|
||
else // Error message will get to client and/or IIS logfiles
|
||
{
|
||
if (String(Request.ServerVariables("REQUEST_METHOD")) == "HEAD")
|
||
{
|
||
__DoLogForm();
|
||
__DoLog("Parameter '" + pName + "' is missing, probably because of unexpected HEAD request", "#FFFF00");
|
||
__DoLog("Useragent: " + Request.ServerVariables("HTTP_USER_AGENT"));
|
||
__DoLog("Referer: " + Request.ServerVariables("HTTP_REFERER"));
|
||
Response.End;
|
||
}
|
||
else
|
||
{
|
||
_AiAi("INTERNAL_ERROR, parameter " + pName + " is missing"); // geen .format gebruiken!
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Check for parameter pName and return the Integer value
|
||
// If not specified return defVal
|
||
// If defVal not specified pName is a required parameter
|
||
// If relaxed==true then return defVal on invalid number
|
||
function getQParamInt(pName, defVal, relaxed)
|
||
{
|
||
return _get_ParamInt(Request.Querystring, pName, defVal, relaxed);
|
||
}
|
||
|
||
function getQParamBits(pName, defVal, mask)
|
||
{
|
||
return _get_ParamBits(Request.Querystring, pName, defVal, mask);
|
||
}
|
||
|
||
// only plain ASCII charachters are allowed: a-z, A-Z and digits
|
||
function getQParamSafe(pName, defVal)
|
||
{
|
||
var txt = _get_Param(Request.Querystring, pName, defVal);
|
||
if (txt.match(/[^_a-zA-Z0-9\-]/))
|
||
_AiAi("INTERNAL_ERROR, parameter " + pName + " should be a simple string but is: " + txt); // geen .format gebruiken!
|
||
return txt;
|
||
}
|
||
|
||
// only plain ASCII charachters are allowed: a-z, A-Z and digits
|
||
function getFParamSafe(pName, defVal)
|
||
{
|
||
var txt = _get_Param(Request.Form, pName, defVal);
|
||
if (txt.match(/[^_a-zA-Z0-9\-]/))
|
||
_AiAi("INTERNAL_ERROR, parameter " + pName + " should be a simple string but is: " + txt); // geen .format gebruiken!
|
||
return txt;
|
||
}
|
||
|
||
function getFQParamSafe(pName, defVal)
|
||
{
|
||
return getFParamSafe(pName, getQParamSafe(pName, defVal));
|
||
}
|
||
|
||
function getFParamInt(pName, defVal, relaxed)
|
||
{
|
||
return _get_ParamInt(Request.Form, pName, defVal, relaxed);
|
||
}
|
||
|
||
function getFQParamInt(pName, defVal, relaxed)
|
||
{
|
||
return getFParamInt(pName, getQParamInt(pName, defVal, relaxed), relaxed)
|
||
}
|
||
|
||
function getFParamBits(pName, defVal, mask)
|
||
{
|
||
return _get_ParamBits(Request.Form, pName, defVal, mask);
|
||
}
|
||
|
||
function _get_ParamInt(pColl, pName, defVal, relaxed)
|
||
{
|
||
var strval = _get_Param(pColl, pName, defVal, true); // force: een lege waarde wordt als afwezig beschouwd
|
||
if (strval == "") return defVal;
|
||
if (String(strval).toLowerCase() == "self") return user_key;
|
||
if (strval == defVal) return defVal;
|
||
if (relaxed)
|
||
strval = String(strval).replace(/[^0-9]*/, ''); // strip leading non-digits
|
||
if (String(strval).substr(0,2)=='0x')
|
||
var val = parseInt(strval);
|
||
else
|
||
var val = parseInt(strval, 10);
|
||
if (isNaN(val))
|
||
{
|
||
if (relaxed)
|
||
return defVal;
|
||
else
|
||
// Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, parameter " + pName + " should be integer but is: " + strval);
|
||
}
|
||
else
|
||
return val;
|
||
}
|
||
|
||
function _get_ParamBits(pColl, pName, defVal, mask) {
|
||
mask = typeof mask === "undefined" ? 8 : mask;
|
||
var result = 0;
|
||
var foundAny = false;
|
||
for (var i = 1; i <= mask; i = i * 2) {
|
||
foundAny |= _has_Param(pColl, "has_" + pName + "_" + i) ? true : false;
|
||
if (_has_Param(pColl, "has_" + pName + "_" + i) && _get_Param(pColl, pName + "_" + i, "off") == "on") {
|
||
result += i;
|
||
}
|
||
}
|
||
return foundAny ? result : defVal;
|
||
}
|
||
|
||
// Check for parameter pName and return the Float value
|
||
// If not specified return defVal
|
||
// If defVal not specified pName is a required parameter
|
||
// If relaxed==true then return defVal on invalid number
|
||
function getQParamFloat(pName, defVal, relaxed)
|
||
{
|
||
return _get_ParamFloat(Request.Querystring, pName, defVal, relaxed)
|
||
}
|
||
function getFParamFloat(pName, defVal, relaxed)
|
||
{
|
||
return _get_ParamFloat(Request.Form, pName, defVal, relaxed)
|
||
}
|
||
function _get_ParamFloat(pColl, pName, defVal, relaxed)
|
||
{
|
||
var strval = _get_Param(pColl, pName, defVal);
|
||
if (strval == "") return defVal;
|
||
if (strval == defVal) return defVal;
|
||
var val = parseFloat(strval.replace(/,/g,"."));
|
||
if (isNaN(val) || !isFinite(val))
|
||
{
|
||
if (relaxed)
|
||
return defVal;
|
||
else
|
||
// Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, parameter {0} should be float but is: {1}".format(pName, strval));
|
||
}
|
||
else
|
||
return val;
|
||
}
|
||
|
||
// Check for parameter pName and return the Date value
|
||
// If not specified return defVal
|
||
// If defVal not specified pName is a required parameter
|
||
// defVal can be a date object or null
|
||
function getQParamDate(pName, defVal)
|
||
{
|
||
return _get_ParamDate(Request.Querystring, pName, defVal)
|
||
}
|
||
function getFParamDate(pName, defVal)
|
||
{
|
||
return _get_ParamDate(Request.Form, pName, defVal)
|
||
}
|
||
function getFQParamDate(pName, defVal)
|
||
{
|
||
return getFParamDate(pName, getQParamDate(pName, defVal))
|
||
}
|
||
function _get_ParamDate(pColl, pName, defVal)
|
||
{
|
||
var txt_val = _get_Param(pColl, pName, ""); // bijvoorbeeld date_from=mp3 voor begin maand, previous, 3
|
||
if (txt_val && !txt_val.match(/^[\-0-9]/)) // begint niet met een cijfer of -1?
|
||
{
|
||
var val = defaultDate(txt_val);
|
||
if (val)
|
||
return val;
|
||
}
|
||
var val = _get_ParamInt(pColl, pName, -1);
|
||
if (val>0 && val<=8640000000000000)
|
||
return new Date(val);
|
||
|
||
if (defVal instanceof Date)
|
||
return defVal;
|
||
|
||
if (defVal === null) // bewust triple===
|
||
{
|
||
return null;
|
||
}
|
||
// Error message will get to client and/or IIS logfiles
|
||
if (String(Request.ServerVariables("REQUEST_METHOD")) == "HEAD")
|
||
{
|
||
__DoLog("Parameter '" + pName + "' should be date, probably because of unexpected HEAD request", "#FFFF00");
|
||
__DoLog("Useragent: " + Request.ServerVariables("HTTP_USER_AGENT"));
|
||
__DoLog("Referer: " + Request.ServerVariables("HTTP_REFERER"));
|
||
Response.End;
|
||
}
|
||
_AiAi("INTERNAL_ERROR, parameter {0} should be date but is: {1}".format(pName, val));
|
||
}
|
||
|
||
// Check for parameter pName and return all values
|
||
// Levert een array op, eventueel leeg
|
||
// Controleert dat het Integers zijn
|
||
// Ondersteunt beide formaten: &key=1&key=2&key=3&key=4 etc.
|
||
// en ook: &key=1,2,3,4
|
||
function getQParamIntArray(pName, defVal, pAll)
|
||
{
|
||
return _get_ParamIntArray(Request.Querystring, pName, defVal, pAll)
|
||
}
|
||
function getFParamIntArray(pName, defVal, pAll)
|
||
{
|
||
return _get_ParamIntArray(Request.Form, pName, defVal, pAll)
|
||
}
|
||
function getFQParamIntArray(pName, defVal, pAll)
|
||
{
|
||
return getFParamIntArray(pName, getQParamIntArray(pName, defVal, pAll), pAll)
|
||
}
|
||
function _get_ParamIntArray(pColl, pName, defVal, pAll)
|
||
{
|
||
var rf = pColl(pName);
|
||
var arr = [];
|
||
if (rf.count > 0 && rf(1) !== "")
|
||
{
|
||
var i;
|
||
for (i=1; i <= rf.count; i++)
|
||
{
|
||
if (rf(i).indexOf(",") >= 0)
|
||
{
|
||
arr = arr.concat(rf(i).split(","));
|
||
}
|
||
else if (rf(i) != "")
|
||
{
|
||
arr.push(rf(i));
|
||
}
|
||
}
|
||
// Nu nog conversie/controle naar integers
|
||
for (i in arr)
|
||
{
|
||
if (String(arr[i]).toLowerCase() == "self")
|
||
{
|
||
arr[i] = user_key;
|
||
}
|
||
else
|
||
{
|
||
arr[i] = parseInt(arr[i], 10);
|
||
}
|
||
if (isNaN(arr[i]))
|
||
{
|
||
_AiAi("INTERNAL_ERROR, ParamIntArray parameter " + pName + " should be all integer"); // geen .format gebruiken!
|
||
}
|
||
}
|
||
if (arr.length == 1 && arr[0] == -1 && !pAll)
|
||
arr = []; // *alleen* -1 betekent vaak dat iemand 'alle' gekozen heeft
|
||
// dat behandelen we effectief als een leeg array
|
||
// Met pAll=true wordt een array met alleen de waarde -1 wel toegestaan.
|
||
}
|
||
if (arr.length)
|
||
return arr;
|
||
else
|
||
{
|
||
if (typeof defVal != 'undefined')
|
||
return defVal;
|
||
else // Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, ParamIntArray parameter " + pName + " is missing"); // geen .format gebruiken!
|
||
}
|
||
}
|
||
|
||
// Bij key array de -1 waarde er tussen uit halen.
|
||
function getQParamKeyArray(pName, defVal, pAll)
|
||
{
|
||
var arr = _get_ParamIntArray(Request.Querystring, pName, defVal, pAll)
|
||
var index = sharedIndexOf(-1, arr);
|
||
if (index > -1) arr.splice(index, 1);
|
||
return arr;
|
||
}
|
||
function getFParamKeyArray(pName, defVal, pAll)
|
||
{
|
||
var arr = _get_ParamIntArray(Request.Form, pName, defVal, pAll)
|
||
var index = sharedIndexOf(-1, arr);
|
||
if (index > -1) arr.splice(index, 1);
|
||
return arr;
|
||
}
|
||
function getFQParamKeyArray(pName, defVal, pAll)
|
||
{
|
||
return getFParamKeyArray(pName, getQParamKeyArray(pName, defVal, pAll), pAll);
|
||
}
|
||
// Bij string array de "-1" waarde er tussen uit halen.
|
||
function getQParamStringArray(pName, defVal, pAll)
|
||
{
|
||
var arr = _get_ParamArray(Request.Querystring, pName, defVal, pAll)
|
||
var index = sharedIndexOf("-1", arr);
|
||
if (index > -1) arr.splice(index, 1);
|
||
return arr;
|
||
}
|
||
function getFParamStringArray(pName, defVal, pAll)
|
||
{
|
||
var arr = _get_ParamArray(Request.Form, pName, defVal, pAll)
|
||
var index = sharedIndexOf("-1", arr);
|
||
if (index > -1) arr.splice(index, 1);
|
||
return arr;
|
||
}
|
||
|
||
function getQParamFloatArray(pName, defVal, pAll)
|
||
{
|
||
return _get_ParamFloatArray(Request.Querystring, pName, defVal, pAll)
|
||
}
|
||
function getFParamFloatArray(pName, defVal, pAll)
|
||
{
|
||
return _get_ParamFloatArray(Request.Form, pName, defVal, pAll)
|
||
}
|
||
function _get_ParamFloatArray(pColl, pName, defVal, pAll)
|
||
{
|
||
var rf = pColl(pName);
|
||
var arr = [];
|
||
if (rf.count > 0 && rf(1) !== "")
|
||
{
|
||
var i;
|
||
for (i=1; i <= rf.count; i++)
|
||
{
|
||
if (rf(i).indexOf(",") >= 0)
|
||
{
|
||
arr = arr.concat(rf(i).split(","));
|
||
}
|
||
else if (rf(i) != "")
|
||
{
|
||
arr.push(rf(i));
|
||
}
|
||
}
|
||
// Nu nog conversie/controle naar floats
|
||
for (i in arr)
|
||
{
|
||
if (String(arr[i]).toLowerCase() == "self")
|
||
{
|
||
arr[i] = user_key;
|
||
}
|
||
else
|
||
{
|
||
arr[i] = parseFloat(arr[i], 10);
|
||
}
|
||
if (isNaN(arr[i]))
|
||
{
|
||
_AiAi("INTERNAL_ERROR, ParamFloatArray parameter {0} should be all float".format(pName));
|
||
}
|
||
}
|
||
if (arr.length == 1 && arr[0] == -1 && !pAll)
|
||
arr = []; // *alleen* -1 betekent vaak dat iemand 'alle' gekozen heeft
|
||
// dat behandelen we effectief als een leeg array
|
||
// Met pAll=true wordt een array met alleen de waarde -1 wel toegestaan.
|
||
}
|
||
if (arr.length)
|
||
return arr;
|
||
else
|
||
{
|
||
if (typeof defVal != 'undefined')
|
||
return defVal;
|
||
else // Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, ParamFloatArray parameter {0} is missing".format(pName));
|
||
}
|
||
}
|
||
|
||
|
||
// Check for parameter pName and return all values
|
||
// Levert een array op, eventueel leeg
|
||
// Als de xxxIntxxx variant maar dan zonder controle dat het Integers zijn
|
||
// Ondersteunt beide formaten: &key=E&key=I&key=L&key=A etc.
|
||
// en ook: &key=E,I,L,A
|
||
// Bij nosplit wordt alleen de eerste ondersteund
|
||
function getQParamArray(pName, defVal, nosplit)
|
||
{
|
||
return _get_ParamArray(Request.Querystring, pName, defVal, nosplit)
|
||
}
|
||
function getFParamArray(pName, defVal, nosplit)
|
||
{
|
||
return _get_ParamArray(Request.Form, pName, defVal, nosplit)
|
||
}
|
||
function getFQParamArray(pName, defVal, nosplit)
|
||
{
|
||
return getFParamArray(pName, getQParamArray(pName, defVal, nosplit), nosplit)
|
||
}
|
||
function _get_ParamArray(pColl, pName, defVal, nosplit)
|
||
{
|
||
var rf = pColl(pName);
|
||
if (rf.count > 0 && rf(1) !== "")
|
||
{
|
||
var arr = [];
|
||
var i;
|
||
for (i=1; i <= rf.count; i++)
|
||
{
|
||
if (!nosplit && rf(i).indexOf(",") >= 0)
|
||
{
|
||
arr = arr.concat(rf(i).split(","));
|
||
}
|
||
else
|
||
arr.push(rf(i));
|
||
}
|
||
return arr;
|
||
}
|
||
else
|
||
{
|
||
if (typeof defVal != 'undefined')
|
||
return defVal;
|
||
else // Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, ParamArray parameter {0} is missing".format(pName));
|
||
}
|
||
}
|
||
|
||
// Check for parameter pName and return all values
|
||
// Levert een array op, eventueel leeg
|
||
// Controleert dat het Datums zijn
|
||
// Ondersteunt beide formaten: &key=1&key=2&key=3&key=4 etc.
|
||
// en ook: &key=1,2,3,4
|
||
function getQParamDateArray(pName, defVal)
|
||
{
|
||
return _get_ParamDateArray(Request.Querystring, pName, defVal)
|
||
}
|
||
function getFParamDateArray(pName, defVal)
|
||
{
|
||
return _get_ParamDateArray(Request.Form, pName, defVal)
|
||
}
|
||
function _get_ParamDateArray(pColl, pName, defVal)
|
||
{
|
||
var rf = pColl(pName);
|
||
if (rf.count > 0)
|
||
{
|
||
var arr = [];
|
||
var i;
|
||
for (i=1; i <= rf.count; i++)
|
||
{
|
||
if (rf(i).indexOf(",") >= 0)
|
||
{
|
||
arr = arr.concat(rf(i).split(","));
|
||
}
|
||
else if (rf(i) != "")
|
||
{
|
||
arr.push(rf(i));
|
||
}
|
||
}
|
||
// Nu nog conversie/controle naar integers
|
||
for (i in arr)
|
||
{
|
||
arr[i] = new Date(parseInt(arr[i], 10));
|
||
if (!(arr[i] instanceof Date || arr[i] === null)) // bewust triple===
|
||
{
|
||
// Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, parameter {0} should be a date Array".format(pName));
|
||
}
|
||
}
|
||
return arr;
|
||
}
|
||
else
|
||
{
|
||
if (typeof defVal != 'undefined')
|
||
return defVal;
|
||
else // Error message will get to client and/or IIS logfiles
|
||
_AiAi("INTERNAL_ERROR, ParamDateArray parameter {0} is missing".format(pName));
|
||
}
|
||
}
|
||
|
||
// Usage: "Wilt U melding {0} afmelden?".format(12345)
|
||
// Localscripts/iface.js heeft de clientside versie
|
||
String.prototype.format = function() {
|
||
var args = arguments;
|
||
return this.replace(/\{(\d+)\}/gi, function (match, d) {
|
||
return args.length > d ? args[d] : match;
|
||
});
|
||
};
|
||
|
||
// lijst is een array van parameter namen ["loc_key", "geb_key", "test"]
|
||
// params is optioneel een hash { loc_key: 345, geb_key: 34 }
|
||
// (zonder params wordt QueryString genomen)
|
||
// resultaat: "&loc_key=345&geb_key=34&test=1&test=2"
|
||
function buildTransitParam(lijst, params)
|
||
{
|
||
var result = "";
|
||
if (typeof lijst == "string")
|
||
lijst = lijst.split(",");
|
||
for (var i = 0; i < lijst.length; i++)
|
||
{
|
||
var itm = lijst[i];
|
||
if (params && params[itm]) // meegegeven
|
||
result = result + "&" + itm + "=" + Server.URLencode(params[itm]);
|
||
else
|
||
{
|
||
var urlparams = Request.QueryString(itm);
|
||
|
||
if (urlparams.count > 0)
|
||
{ // Waarde is meegegeven, dan ook doorgeven.
|
||
// Voeg elke waarde als aparte string waarde toe.
|
||
for (var j = 1; j <= urlparams.count; j++)
|
||
{
|
||
result += "&" + itm + "=" + Server.URLencode(urlparams(j));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// Op een XSS veilige manier de complete QueryString door kunnen geven
|
||
function transitQS()
|
||
{
|
||
var result = "";
|
||
for (var i = 1; i <= Request.QueryString.count; i++)
|
||
{
|
||
var itm = Request.QueryString.key(i);
|
||
var urlparams = Request.QueryString.item(i);
|
||
var hasHMAC = Request.QueryString("hmac").Count > 0;
|
||
var safe_itm;
|
||
var safe_urlparam;
|
||
// Nu de waarde of waarden goed uitlezen.
|
||
// urlparams kan uit meerdere waarden bestaan. Als string staan er dan extra spaties achter de komma's.
|
||
// Voeg elke waarde als aparte string waarde toe.
|
||
for (var j = 1; j <= urlparams.count; j++)
|
||
{
|
||
if (hasHMAC)
|
||
{
|
||
safe_itm = itm; // anders wordt een underscore in &mld_key een %5F en klopt de hmac niet meer
|
||
safe_urlparam = urlparams(j);
|
||
}
|
||
else
|
||
{
|
||
safe_itm = Server.URLencode(itm);
|
||
safe_urlparam = Server.URLencode(urlparams(j));
|
||
}
|
||
result += "&" + safe_itm + "=" + safe_urlparam;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
function padout(number) { return (number < 10) ? "0" + number : number; }
|
||
|
||
/**************************
|
||
* Timezone-perikelen *
|
||
***************************/
|
||
function oRaAsUserTZ(prefix, varName, isGroupClause)
|
||
{
|
||
if (prefix != "")
|
||
prefix += ".";
|
||
|
||
/////
|
||
// Returns;
|
||
// for GROUP BY Clause: the same prefix + "." + varName
|
||
// for SELECT Clause: the same prefix + "." + varName with correct syntax and an Alias as + "_tz"
|
||
/////
|
||
if (Session("time_zone") == S("fac_server_timezone"))
|
||
return (isGroupClause ? "" : " , ")
|
||
+ prefix + varName
|
||
+ (isGroupClause ? "" : " " + varName + "_tz");
|
||
|
||
/////
|
||
// Returns;
|
||
// for GROUP BY Clause: syntax for converted time-zone
|
||
// for SELECT Clause: syntax for converted time-zone with comma for SELECT Clause, named: [varName + "_tz"]
|
||
/////
|
||
return (isGroupClause ? "" : " , ")
|
||
+ "CAST(FROM_TZ(CAST(" + prefix + varName + " AS TIMESTAMP), TO_CHAR (SYSTIMESTAMP, 'tzr')) AT TIME ZONE SESSIONTIMEZONE AS DATE)"
|
||
+ (isGroupClause ? "" : " " + varName + "_tz");
|
||
}
|
||
|
||
function getServerHour(h)
|
||
{
|
||
var tempDate = new Date();
|
||
tempDate.setHours(h);
|
||
tempDate = convertToServerTime(tempDate);
|
||
return tempDate.getHours();
|
||
}
|
||
|
||
function getUserHour(h)
|
||
{
|
||
var tempDate = new Date();
|
||
tempDate.setHours(h);
|
||
tempDate = convertToLocalTime(tempDate);
|
||
return tempDate.getHours();
|
||
}
|
||
|
||
// Local time-zone = alg_locatie_timezone
|
||
// User time-zone = Session("time_zone")
|
||
// Server time-zone = S("fac_server_timezone")
|
||
|
||
// Datetime van alg_locatie of user-tijdszone omzetten naar de server tijdszone
|
||
function convertToServerTime(userDateTime, localTimezone) {
|
||
if (!localTimezone) {
|
||
localTimezone = Session("time_zone"); // 'Local' = user timezone by default (= indien leeg)
|
||
}
|
||
return convertTimeZone(userDateTime, localTimezone, S("fac_server_timezone"));
|
||
}
|
||
|
||
// Datetime van server tijdszone omzetten naar de alg_locatie of user-tijdszone
|
||
function convertToLocalTime(serverDateTime, localTimezone) {
|
||
if (!localTimezone) {
|
||
localTimezone = Session("time_zone"); // 'Local' = user timezone by default (= indien leeg)
|
||
}
|
||
return convertTimeZone(serverDateTime, S("fac_server_timezone"), localTimezone);
|
||
}
|
||
|
||
function convertTimeZone(thisDate, fromTZ, toTZ)
|
||
{
|
||
|
||
if (!fromTZ || !toTZ || fromTZ.toUpperCase() == toTZ.toUpperCase())
|
||
return thisDate;
|
||
|
||
var sql = "SELECT CAST ("
|
||
+ "FROM_TZ (CAST ( "+thisDate.toSQL(true)+" AS TIMESTAMP), "+safe.quoted_sql(fromTZ)+")"
|
||
+ " AT TIME ZONE "+safe.quoted_sql(toTZ)+" AS DATE)"
|
||
+ " AS newDate"
|
||
+ " FROM DUAL";
|
||
|
||
var oRs = Oracle.Execute(sql);
|
||
thisDate = new Date(oRs("newDate").value);
|
||
oRs.close();
|
||
|
||
return thisDate;
|
||
|
||
}
|
||
|
||
// This function should only be used to format display,
|
||
// <20> never as part of a computation.
|
||
// Als de jsDate van de user(client) afkomstig is, hoeft er geen conversie naar de user-time-zone plaats te vinden
|
||
function toTimeString(jsDate, bWithSeconds, isLocalTime)
|
||
{
|
||
if (jsDate == null)
|
||
return "";
|
||
|
||
if (typeof jsDate == "object" && jsDate.type == 135/*adDBTimeStamp, oRs("datum")*/)
|
||
jsDate = new Date(jsDate.value);
|
||
if (typeof jsDate == "date") // een oRs("datum").value
|
||
jsDate = new Date(jsDate);
|
||
if (typeof jsDate == "number") // 8.5 voor 08:30
|
||
{
|
||
if (jsDate < 0 || jsDate > 24)
|
||
return "";
|
||
var hh = Math.floor(jsDate);
|
||
var mm = (jsDate*60) % 60;
|
||
jsDate = new Date();
|
||
jsDate.setHours(hh,mm,0,0);
|
||
}
|
||
|
||
if (!jsDate)
|
||
return "";
|
||
|
||
if (!isLocalTime)
|
||
jsDate = convertToLocalTime(jsDate);
|
||
|
||
ret = padout(jsDate.getHours()) + ":" + padout(jsDate.getMinutes());
|
||
if (bWithSeconds) ret += ":" + padout(jsDate.getSeconds());
|
||
return ret;
|
||
}
|
||
// Als de jsDate van de user(client) afkomstig is, hoeft er geen conversie naar de user-time-zone plaats te vinden
|
||
function toDateString(jsDate, noDay, pretty, isLocalDate)
|
||
{
|
||
var resstr = "";
|
||
var today = new Date().midnight();
|
||
var yesterday = (new Date(today))
|
||
yesterday.setDate(today.getDate()-1);
|
||
var tomorrow = (new Date(today));
|
||
tomorrow.setDate(today.getDate()+1);
|
||
|
||
if (jsDate == null)
|
||
return "";
|
||
|
||
if (typeof jsDate == "object" && jsDate.type == 135/*adDBTimeStamp, oRs("datum")*/)
|
||
jsDate = new Date(jsDate.value);
|
||
|
||
if (typeof jsDate == "date") // een oRs("datum").value
|
||
jsDate = new Date(jsDate);
|
||
|
||
if (!jsDate)
|
||
return "";
|
||
|
||
if (!isLocalDate)
|
||
jsDate = convertToLocalTime(jsDate);
|
||
|
||
// Ik wil graag, alleen als parameter friendly?, voor de datums gisteren, vandaag en morgen de tekst Gisteren, Vandaag en Morgen opleveren
|
||
// Voor lijsten/sortering is dat vaak niet handig, maar soms is het veel begrijpelijker. Als de mogelijkheid er is, kunnen we
|
||
// geleidelijk de toepassing uitbreiden. In Lopende zaken op de portal om mee te beginnen.
|
||
|
||
if (pretty && jsDate.midnight().getTime() == today.getTime())
|
||
resstr = L("lcl_date_today");
|
||
else if (pretty && jsDate.midnight().getTime() == yesterday.getTime())
|
||
resstr = L("lcl_date_yesterday");
|
||
else if (pretty && jsDate.midnight().getTime() == tomorrow.getTime())
|
||
resstr = L("lcl_date_tomorrow");
|
||
else
|
||
resstr = (noDay?"":calendar_names.daysMin[jsDate.getDay()] + " ") +
|
||
padout(jsDate.getDate()) + "-" + padout(jsDate.getMonth() + 1) + "-" + padout(jsDate.getFullYear());
|
||
|
||
return resstr;
|
||
}
|
||
function toDateTimeString(jsDate, bWithSeconds, noDay, prettyday, noMidnight, isLocalDate)
|
||
{
|
||
if (jsDate == null)
|
||
return "";
|
||
|
||
if (typeof jsDate == "object" && jsDate.type == 135/*adDBTimeStamp, oRs("datum")*/)
|
||
jsDate = new Date(jsDate.value);
|
||
|
||
if (typeof jsDate == "date") // een oRs("datum").value
|
||
jsDate = new Date(jsDate);
|
||
|
||
if (!isLocalDate) {
|
||
jsDate = convertToLocalTime(jsDate);
|
||
}
|
||
|
||
if (noMidnight && jsDate.getTime() == jsDate.midnight().getTime())
|
||
return toDateString(jsDate, noDay, prettyday, true)
|
||
else
|
||
return toDateString(jsDate, noDay, prettyday, true) + " " + toTimeString(jsDate, bWithSeconds, true)
|
||
}
|
||
|
||
function defaultDate(code)
|
||
{
|
||
if (!code)
|
||
return null;
|
||
|
||
_getMonday = function (d) {
|
||
d = new Date(d);
|
||
var day = d.getDay(),
|
||
diff = d.getDate() - day + (day == 0 ? -6:1); // adjust when day is sunday
|
||
return new Date(d.setDate(diff));
|
||
}
|
||
|
||
var dt = null;
|
||
var pn = code.substr(1,1); // p is dag terug, n is dag vooruit
|
||
var pnnum = (pn=='p'?-1:pn=='n'?1:0);
|
||
if (pn != 0)
|
||
pnnum *= (parseInt(code.substr(2), 10) || 1);
|
||
switch (code.substr(0,1).toLowerCase())
|
||
{
|
||
case "n":
|
||
dt = new Date();
|
||
break;
|
||
case "d":
|
||
dt = new Date();
|
||
dt.setHours(0,0,0,0);
|
||
dt.setDate(dt.getDate() + pnnum);
|
||
break;
|
||
case "w":
|
||
dt = _getMonday(new Date());
|
||
dt.setHours(0,0,0,0);
|
||
dt.setDate(dt.getDate() + pnnum * 7);
|
||
break;
|
||
case "m":
|
||
dt = new Date();
|
||
dt.setDate(1);
|
||
dt.setHours(0,0,0,0);
|
||
dt.setMonth(dt.getMonth() + pnnum);
|
||
break;
|
||
case "q":
|
||
dt = new Date();
|
||
dt.setDate(1);
|
||
dt.setHours(0,0,0,0);
|
||
dt.setMonth(3 * Math.floor(dt.getMonth() / 3));
|
||
dt.setMonth(dt.getMonth() + pnnum * 3);
|
||
break;
|
||
case "y":
|
||
dt = new Date();
|
||
dt.setDate(1);
|
||
dt.setMonth(0);
|
||
dt.setHours(0,0,0,0);
|
||
dt.setYear(dt.getYear() + pnnum);
|
||
break;
|
||
}
|
||
|
||
// Nu correctie naar einde periode voor hoofdletter
|
||
switch (code.substr(0,1))
|
||
{
|
||
case "N":
|
||
break;
|
||
case "D":
|
||
dt.setDate(1 + dt.getDate());
|
||
break;
|
||
case "W":
|
||
dt.setDate(7 + dt.getDate());
|
||
break;
|
||
case "M":
|
||
dt.setMonth(1 + dt.getMonth());
|
||
break;
|
||
case "Q":
|
||
dt.setMonth(3 + dt.getMonth());
|
||
break;
|
||
case "Y":
|
||
dt.setYear(1 + dt.getYear());
|
||
break;
|
||
}
|
||
// Onderstaande pas *na* voorgaande om problemen
|
||
// met maanden van 30 dagen te voorkomen
|
||
if (code.substr(0,1) != code.substr(0,1).toLowerCase())
|
||
dt.setHours(0,0,-1,0); // Einde dag ervoor
|
||
|
||
return dt;
|
||
}
|
||
|
||
function user_time_based_greeting() {
|
||
var uur = convertToLocalTime(new Date()).getHours();
|
||
if (uur == 24 || uur < 6) {
|
||
return L("lcl_greet_night");
|
||
} else if (uur < 12) {
|
||
return L("lcl_greet_morning");
|
||
} else if (uur < 18) {
|
||
return L("lcl_greet_afternoon");
|
||
} else if (uur < 24) {
|
||
return L("lcl_greet_evening");
|
||
}
|
||
}
|
||
|
||
// vertaalt een CSS-achtige color naar een pure hexcode van 6 posities
|
||
// mag naar hartelust uitgebreid worden. Typische toepassing is het sanitizen
|
||
// van een kleur uit de database of setting naar een gebruik waar zuivere hexcode nodig is.
|
||
// Die mag dan weer met een parseInt,16 worden omgezet naar decimaal als je zou willen
|
||
function toHexValue(colorString, params)
|
||
{
|
||
params = params || {};
|
||
colorString = colorString || "010101";
|
||
var retval;
|
||
if (colorString && colorString.substring(0,1) == "#")
|
||
retval = colorString.substring(1);
|
||
else
|
||
retval = colorString;
|
||
if (params.autobackground)
|
||
{
|
||
var R = parseInt(retval.substr(0, 2), 16);
|
||
var G = parseInt(retval.substr(2, 2), 16);
|
||
var B = parseInt(retval.substr(4, 2), 16);
|
||
if (Math.pow(255.0 - R,2) +
|
||
Math.pow(255.0 - G,2) +
|
||
Math.pow(255.0 - B,2) >
|
||
Math.pow(R, 2.0) +
|
||
Math.pow(G, 2.0) +
|
||
Math.pow(B, 2.0)) // dark
|
||
{
|
||
retval += ",FEFEFE,FF";
|
||
}
|
||
else
|
||
{
|
||
retval += ",010101,FF";
|
||
}
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
// Maakt gebruik van de sanatize-functie hierboven, en zet de resulterende hexcode om naar een RGB/RGBA-kleur
|
||
function toRgb(colorString, params) {
|
||
params = params || {};
|
||
var hexColorString = toHexValue(colorString); // Zonder params
|
||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColorString);
|
||
var ret = parseInt(result[1], 16) + ", "
|
||
+ parseInt(result[2], 16) + ", "
|
||
+ parseInt(result[3], 16);
|
||
if (params.alpha) {
|
||
return "rgba(" + ret + ", " + (Math.round(10000 * params.alpha / 256) / 10000) + ")";
|
||
}
|
||
return "rgb(" + ret + ")";
|
||
}
|
||
|
||
// Zie document"z:\Project\Sm44\DOC\Intern\Facilitor5i\Facilitor 5i Quotes en Escape.doc"
|
||
safe = {
|
||
|
||
// getal 0 blijft 0
|
||
nvl: function (x)
|
||
{
|
||
if (x == null)
|
||
return "";
|
||
else
|
||
return x;
|
||
},
|
||
// Deze functie escaped alle karakters die in een regular expression ge-escaped moeten worden
|
||
// Maar doet niets met (single) quotes (!)
|
||
regexp: function(waarde) {
|
||
return safe.nvl(waarde).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||
},
|
||
// Bijvoorbeeld <textarea>< % =safe.textarea(waarde)% ></textarea>
|
||
textarea: function(waarde)
|
||
{
|
||
return Server.HTMLEncode(safe.nvl(waarde));
|
||
},
|
||
// Bijvoorbeeld <div class='fclthtml'>< % =safe.fclthtml(omschr)% ></div>
|
||
// We ondersteunen bb-codes die 1-op-1 naar html zijn om te zetten
|
||
// Let op: deze functie lijkt veel op default.xsl/safe.fclthtml
|
||
// Pas die eventueel ook aan
|
||
fclthtml: function (waarde, params)
|
||
{
|
||
if (!waarde) // early exit
|
||
return "";
|
||
params = params || {};
|
||
var safe_array = [];
|
||
|
||
// Eerst de complexere bb-tags;
|
||
|
||
// Checking for [link] url (|optionaltext) [/link]
|
||
// or [url] url (|optionaltext) [/url]
|
||
var strre = "\\[(link|url)\\](.*?)\\[\\/(?:\\1)\\]";
|
||
var allowedLinkRegex = new RegExp(S("allowedLinkRegex"), "i");
|
||
var matched = waarde.match(new RegExp(strre, "gi"));
|
||
if (matched != null)
|
||
{
|
||
var url = "";
|
||
var label = "";
|
||
for (var i = 0; i < matched.length; i++)
|
||
{
|
||
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
|
||
if (groups)
|
||
{
|
||
// groups[1] = "link" of "url" (wordt verder niet gebruikt)
|
||
// groups[2] = url (|optionaltext)
|
||
var result = groups[2].split("|");
|
||
if (result.length > 0)
|
||
{
|
||
var safe_url = safe.htmlattr(result[0]);
|
||
if (result.length > 2)
|
||
{
|
||
result.shift();
|
||
label = result.join("|");
|
||
}
|
||
else if (result.length == 2)
|
||
label = result[1];
|
||
else
|
||
label = result[0];
|
||
|
||
if (safe_url.match(allowedLinkRegex)) {
|
||
var guid = shared.random(32);
|
||
var safe_str = "<a href=\"" + safe_url + "\" target=\"_blank\" rel=\"noopener noreferrer\">" + safe.fclthtml(label, params) + "</a>";
|
||
if (typeof mobile !== "undefined") {
|
||
safe_str = "<object>" + safe_str + "</object>";
|
||
}
|
||
safe_array.push({
|
||
"guid": guid,
|
||
"safe_str": safe_str
|
||
});
|
||
waarde = waarde.replace(matched[i], guid);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (params.mention)
|
||
{ // Checking for [mention] prs_key | prs_name [/mention] as used in notes
|
||
strre = "\\[mention\\](\\d+)\\|(.+?)\\[\\/mention\\]";
|
||
var matched = waarde.match(new RegExp(strre, "gi"));
|
||
if (matched != null)
|
||
{
|
||
var prs_key = -1;
|
||
var prs_name = "";
|
||
for (var i = 0; i < matched.length; i++)
|
||
{
|
||
var groups = matched[i].match(new RegExp(strre, "i"));
|
||
if (groups) // Zonder 'g'lobal-flag
|
||
{ // groups[1] = prs_key
|
||
// groups[2] = prs_name
|
||
var prs_key = parseInt(groups[1], 10);
|
||
if (groups.length > 2) {
|
||
var guid = shared.random(32);
|
||
var safe_str = "<span class='details' onclick='iface.persoonDetails(null, null, " + prs_key + ")'>@" + safe.html(groups[2]) + "</span>";
|
||
safe_array.push({
|
||
"guid": guid,
|
||
"safe_str": safe_str
|
||
});
|
||
waarde = waarde.replace(matched[i], guid);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Checking for [img] src [/img] */
|
||
strre = "\\[img\\](.*?)\\[\\/img\\]";
|
||
matched = waarde.match(new RegExp(strre, "gi"));
|
||
if (matched != null) {
|
||
if (params.file_params) {
|
||
var props = props || flexProps(params.file_params.module, params.file_params.key, null, null, { getFiles: !(params.file_params.key > 0), cacheablehmac: true });
|
||
for (var i = 0; i < matched.length; i++) {
|
||
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
|
||
if (groups) {
|
||
var file = groups[1];
|
||
if (props && props.files && props.files.length) {
|
||
for (var j = 0; j < props.files.length; j++) {
|
||
if (props.files[j].name === file) {
|
||
var guid = shared.random(32);
|
||
var safe_str = '<img alt="' + safe.htmlattr(props.files[j].name) + '" src="' + safe.htmlattr(props.files[j].deepurl) + '" class="bb-image" onclick="iface.fullscreen_image(this.src)">';
|
||
safe_array.push({
|
||
"guid": guid,
|
||
"safe_str": safe_str
|
||
});
|
||
waarde = waarde.replace(matched[i], guid);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var safehtml = safe.html(waarde); // Let op: vervangt *alle* \n door <br>. Dat gaan we deels later nog terugdraaien
|
||
// We hebben het wel *nodig* omdat .* niet over meerdere regels werkt (hoewel dat
|
||
// weer oplosbaar schijnt te zijn met [\s\S])
|
||
|
||
// Check op [color=#]
|
||
var strre = "\\[color=([#][0-9a-fA-F]{6})\\]([^\\[]*)|\\[\\/color\\]".format(code);
|
||
var strnew = "<span style='color:$1;'>$2</span>";
|
||
var re = new RegExp(strre, "g");
|
||
safehtml = safehtml.replace(re, strnew);
|
||
|
||
// En nu de simpelere bb-tags;
|
||
|
||
// Als je safepairs hieronder aanpast, moet dat ook in stripbbcodes gebeuren
|
||
var safepairs = "h1,h2,h3,h4,h5,h6,b,i,u,s,em,strong,small,big,th,td,tr,table,pre,code".split(",");
|
||
for (var i = 0; i < safepairs.length; i++)
|
||
{
|
||
var code = safepairs[i];
|
||
var strre = "\\[{0}\\](.*?)\\[\\/{0}\\]".format(code); // De ? maakt de .* lazy (ipv greedy)
|
||
var strnew = "<" + code + ">$1</" + code + ">";
|
||
var re = new RegExp(strre, "g");
|
||
safehtml = safehtml.replace(re, strnew);
|
||
}
|
||
|
||
if (params.fcltlinks || params.mldlink)
|
||
var safehtml = safe.mldlinkhtml(safehtml);
|
||
|
||
if (params.fcltlinks || params.cntlink)
|
||
var safehtml = safe.cntlinkhtml(safehtml);
|
||
|
||
if (params.fcltlinks || params.faqlink)
|
||
var safehtml = safe.faqlinkhtml(safehtml);
|
||
|
||
// Nu de <br>'s binnen de tabel terugzetten. Let op dat ze *binnen* <td>'s weer wel moeten blijven
|
||
// TODO: Kan dit beter?
|
||
if (safehtml.indexOf("<table>") > -1)
|
||
{
|
||
var tablepairs = "th,td,tr,table".split(",");
|
||
for (var i = 0; i < tablepairs.length; i++)
|
||
{
|
||
var code = tablepairs[i];
|
||
var re = new RegExp("<{0}>(\r<br>)+".format(code), "g");
|
||
safehtml = safehtml.replace(re, "<" + code + ">");
|
||
re = new RegExp("</{0}>(\r<br>)+".format(code), "g");
|
||
safehtml = safehtml.replace(re, "</" + code + ">");
|
||
}
|
||
}
|
||
|
||
// Nu alle <br>'s binnen <pre> terugzetten
|
||
var matches = safehtml.match(/<pre(?:.*?)>(?:.*?)<\/pre>/g);
|
||
if (!matches)
|
||
matches = safehtml.match(/<code(?:.*?)>(?:.*?)<\/code>/g);
|
||
if (matches)
|
||
{
|
||
var len = matches.length;
|
||
var i;
|
||
for (i = 0; i < len; i++)
|
||
{
|
||
var pre = matches[i];
|
||
pre = pre.replace(/<br(?:.*?)>/g, '\n');
|
||
safehtml = safehtml.replace(matches[i], pre);
|
||
}
|
||
}
|
||
|
||
for (var i in safe_array) {
|
||
safehtml = safehtml.replace(safe_array[i].guid, safe_array[i].safe_str);
|
||
}
|
||
|
||
return safehtml;
|
||
},
|
||
mldlinkhtml: function (safehtml)
|
||
{
|
||
if (!S("mld_autolink_regexp")) /// (?:(?:melding [A-Z]*)|(?:[A-Z]*\#[A-Z]*))(\d*)
|
||
return safehtml;
|
||
|
||
var safehtml = safehtml.replace(new RegExp(S("mld_autolink_regexp"), "ig"),
|
||
( typeof mobile == "undefined"
|
||
? "<span class='details' onclick='FcltMgr.openDetail("appl/mld/mld_melding.asp?mld_key=$1&", { reuse: true })'>$&</span>"
|
||
: "<span class='details' data-ajax='false' onclick='javascript:document.location.href=\"./melding.asp?mld_key=$1\";return false;'>$&</span>"
|
||
)
|
||
);
|
||
|
||
return safehtml;
|
||
},
|
||
cntlinkhtml: function (safehtml)
|
||
{
|
||
if (!S("cnt_autolink_regexp"))
|
||
return safehtml;
|
||
|
||
var cnt_arr = safehtml.match(new RegExp(S("cnt_autolink_regexp"), "ig"));
|
||
if (cnt_arr)
|
||
{
|
||
for (var i=0; i<cnt_arr.length; i++)
|
||
{
|
||
var cnt_str = cnt_arr[i];
|
||
var cnt_num = cnt_str.substr(cnt_str.indexOf(" ") + 1);
|
||
var sql = "SELECT cnt_contract_key"
|
||
+ " FROM cnt_v_aanwezigcontract"
|
||
+ " WHERE UPPER(cnt_contract_nummer_intern) = " + safe.quoted_sql_upper(cnt_num)
|
||
+ " ORDER BY cnt_contract_key DESC";
|
||
var oRs = Oracle.Execute(sql);
|
||
if (!oRs.eof)
|
||
{
|
||
var cnt_key = oRs("cnt_contract_key").Value;
|
||
safehtml = safehtml.replace(cnt_str, "<span class='details' onclick='FcltMgr.openDetail("appl/cnt/cnt_contract.asp?cnt_key="+cnt_key+"&", { reuse: true })'>"+cnt_str+"</span>")
|
||
}
|
||
oRs.Close();
|
||
}
|
||
}
|
||
return safehtml;
|
||
},
|
||
faqlinkhtml: function (safehtml)
|
||
{
|
||
if (!S("faq_autolink_regexp"))
|
||
return safehtml;
|
||
|
||
var safehtml = safehtml.replace(new RegExp(S("faq_autolink_regexp"), "ig"),
|
||
"<span class='details' onclick='FcltMgr.openDetail("appl/fac/fac_faq.asp?faq_key=$1&", { reuse: true })'>$&</span>"
|
||
);
|
||
return safehtml;
|
||
},
|
||
notehtml: function(waarde, module, note_key)
|
||
{
|
||
return safe.fclthtml(waarde, { "mldlink": true, "cntlink": true, "faqlink": true, "mention": true, "file_params": { "module": module + "N", "key": note_key } });
|
||
},
|
||
// Bijvoorbeeld <div>< % =safe.html(omschr)% ></div>
|
||
html: function (waarde)
|
||
{
|
||
return Server.HTMLEncode(safe.nvl(waarde)).replace(/\n/g, "<br>");
|
||
},
|
||
// bijvoorbeeld <input value="< % =safe.htmlattr(waarde) % >">
|
||
htmlattr: function (waarde)
|
||
{
|
||
return Server.HTMLEncode(safe.nvl(waarde)).replace(/\'/g,''').replace(/\"/g,'"'); // ' syntax highlight correctie
|
||
},
|
||
// bijvoorbeeld queuemail.asp?subject=" + safe.url(subject)
|
||
url: function (waarde)
|
||
{
|
||
return Server.URLencode(safe.nvl(waarde));
|
||
},
|
||
urlUTF8: function (waarde) // Nodig binnen jQuery mobile. Gebruik tegenhanger getQParamUTF8
|
||
{
|
||
return encodeURIComponent(safe.nvl(waarde));
|
||
},
|
||
// Altijd quotes er om, we verdubbelen interne
|
||
// CR+LF binnen een waarde maken we alleen LF van
|
||
csv: function (waarde)
|
||
{
|
||
if (waarde==null)
|
||
return "";
|
||
return "\"" + String(waarde).replace(/\x0D\x0A/g,'\x0A').replace(/\"/g,'""') + "\""; // " syntax highlight correctie
|
||
},
|
||
// Levert een getal op als string met een komma of een punt, afhankelijk van de
|
||
// decimaal scheider die de gebruiker op zijn eigen PC heeft ingesteld
|
||
// Merk op: g<><67>n 1000-separator, dat is te lastig
|
||
// Te gebruiken voor readonly presentatie van bedragen
|
||
displayfloat: function (fnum, decimals, trimZeros)
|
||
{
|
||
if (fnum == null)
|
||
return "";
|
||
|
||
if (typeof decimals == "undefined")
|
||
decimals = 2;
|
||
fnum = fnum.toFixed(decimals);
|
||
var waarde2 = (1.5).toLocaleString(); // Eventueel gewenste komma, dank zij LCID gezet in appl\FAC\facilitor.inc
|
||
fnum = fnum.substring(0, fnum.length - decimals - 1) + waarde2.substring(2, 1) + fnum.substring(fnum.length - decimals);
|
||
if (trimZeros)
|
||
{
|
||
while (fnum.substring(fnum.length-1) == "0")
|
||
fnum = fnum.substring(0, fnum.length-1);
|
||
if (fnum.substring(fnum.length-1) == waarde2.substring(2, 1))
|
||
fnum = fnum.substring(0, fnum.length-1);
|
||
}
|
||
return fnum;
|
||
},
|
||
// Levert een getal op als string met een komma of een punt, afhankelijk van de
|
||
// decimaal scheider die de gebruiker op zijn eigen PC heeft ingesteld
|
||
// Inclusief 1000-separator (Ook afhanklijk van de gebruiker)
|
||
// Te gebruiken voor readonly presentatie van bedragen
|
||
// Accepteert Number of String met 0 of 1 punt als decimaal scheider. (geen komma's dus)
|
||
// Geeft maximaal 2 decimalen terug; onze toLocaleString ondersteunt nog geen maximumFractionDigits
|
||
showFloat: function (fnum, decimals, trimZeros)
|
||
{
|
||
if (fnum == null || isNaN(fnum))
|
||
return fnum;
|
||
if (typeof decimals == "undefined" || isNaN(decimals))
|
||
decimals = 2; // default = 2
|
||
|
||
// Maak er een String van op 2 decimalen, en rond alvast op de juiste decimaal af
|
||
var factor = Math.pow(10, decimals);
|
||
fnum = Math.round(fnum*factor)/factor;
|
||
fnum = fnum.toLocaleString();
|
||
|
||
// Trim de onnodige decimalen
|
||
if (decimals == 1)
|
||
fnum = fnum.substring(0, fnum.length-1);
|
||
else if (decimals == 0)
|
||
fnum = fnum.substring(0, fnum.length-3);
|
||
|
||
// Trim de evt. nullen
|
||
var decimalSign = (1.5).toLocaleString().substring(2, 1); // Eventueel gewenste komma, dank zij LCID gezet in appl\FAC\facilitor.inc
|
||
if (trimZeros && decimals > 0)
|
||
{
|
||
while (fnum.substring(fnum.length-1) == "0")
|
||
fnum = fnum.substring(0, fnum.length-1);
|
||
if (fnum.substring(fnum.length-1) == decimalSign)
|
||
fnum = fnum.substring(0, fnum.length-1);
|
||
}
|
||
return fnum;
|
||
},
|
||
// luxe variant: gewenste punt/komma en ook duizendscheiders
|
||
curr: function (waarde, nocents)
|
||
{
|
||
return safe.showFloat(waarde, (nocents ? 0 : 2), false);
|
||
},
|
||
// Editable willen we er echt geen duizend-scheiders in hebben
|
||
// Die zijn namelijk heel moeilijk terug te converteren naar number
|
||
// Te gebruiken voor bewerkbare velden met bedragen
|
||
editablefloat: function(fnum, decimals)
|
||
{
|
||
return safe.displayfloat(fnum, decimals); // die heeft toch geen duizend-scheiders
|
||
},
|
||
curreditable: function (waarde)
|
||
{
|
||
return safe.editablefloat(waarde, 2);
|
||
},
|
||
// FcltMgr.alert("< % =safe.jsstring(waarde) % >")
|
||
// </script> is ook funest!
|
||
jsstring: function (waarde)
|
||
{
|
||
return (safe.nvl(waarde)).replace(/\\/g,'\\\\').replace(/\n/g,'\\n')
|
||
.replace(/\r/g,'').replace(/\'/g,'\\x27').replace(/\"/g,'\\x22')
|
||
.replace(/\</g, '\\x3C').replace(/\>/g, '\\x3E'); // ' syntax highlight correctie
|
||
},
|
||
// var S("res_t1")=< % =safe.jsfloat(S("res_t1"))% >
|
||
jsfloat: function (fnum)
|
||
{
|
||
return(String(fnum)).replace(',','.');
|
||
},
|
||
quoted_sql: function (tekst, maxlen) // maxlen is optioneel
|
||
{
|
||
if (tekst == null)
|
||
return "NULL";
|
||
if (!maxlen)
|
||
maxlen = 4000;
|
||
// Haal alle lage bytes (muv TAB (x09), LF (x0A) en CR (x0D)) er uit. Die representeren
|
||
// geen geldig karakter in Windows-1252 of iso-8859. Ook in UTF-8 staan ze niet voor
|
||
// tekst, mochten we dat ooit willen gaan ondersteunen.
|
||
// Voor ultieme veiligheid ook maar de hoge unicodes er uit? Neen, EURO is ten slotte
|
||
// ook een 'hoge' unicode
|
||
tekst = tekst.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]+/g, "?");
|
||
tekst = tekst.substr(0, maxlen);
|
||
// FSN#35288: '{' naar CHR(123) voorkomt Unspecified Error
|
||
return "'" + tekst.replace(/\'/g,"''").replace(/\{/g,"'||CHR(123)||'") + "'"; // " syntax highlight correctie
|
||
},
|
||
qL: function (p_lcl, params)
|
||
{
|
||
return safe.quoted_sql((L(p_lcl, params)));
|
||
},
|
||
|
||
quoted_sql_join: function (tekstarr, toupper) // Vooral voor IN () clausules met tekstwaardes
|
||
{
|
||
if (!tekstarr || !tekstarr.length)
|
||
return "NULL";
|
||
|
||
var safearr = [];
|
||
for (var i = 0; i < tekstarr.length; i++)
|
||
{
|
||
safearr.push(toupper? safe.quoted_sql_upper(tekstarr[i]) : safe.quoted_sql(tekstarr[i]))
|
||
}
|
||
return safearr.join(", ");
|
||
},
|
||
|
||
quoted_sql_upper: function (tekst, maxlen)
|
||
{
|
||
if (tekst == null)
|
||
return "NULL";
|
||
return safe.quoted_sql(tekst.toUpperCase(), maxlen);
|
||
},
|
||
|
||
quoted_sql_wild: function (tekst, maxlen)
|
||
{
|
||
if (tekst == null)
|
||
return "NULL";
|
||
return safe.quoted_sql(tekst.toUpperCase().replace(/\*/g, "%"), maxlen);
|
||
},
|
||
|
||
quoted_sql_wild2: function (tekst)
|
||
{
|
||
if (tekst == null)
|
||
return "NULL";
|
||
var zoektekst = tekst.toUpperCase();
|
||
switch (S("use_wildcard_with_suggests"))
|
||
{
|
||
case 0: break; // geen wildcard gebruiken
|
||
case 1: zoektekst = zoektekst + "%"; break;
|
||
case 2: zoektekst = "%" + zoektekst + "%"; break;
|
||
}
|
||
return safe.quoted_sql(zoektekst.replace(/\*/g, "%"));
|
||
},
|
||
|
||
// converteer alle waarden in arr naar integer.
|
||
// waar dat niet lukt worden ze gewoon verwijderd(?)
|
||
int_array: function (arr)
|
||
{
|
||
var safe_arr = [];
|
||
for (var i = 0; i < arr.length; i++)
|
||
{
|
||
var v = parseInt(arr[i], 10);
|
||
if (!isNaN(v))
|
||
safe_arr.push(v);
|
||
}
|
||
return safe_arr;
|
||
},
|
||
|
||
filename: function (naam) // geen 'lage' karakters en geen (back)slashes, *,%,<,>, '"', ':', ';' '?' and '|' of '+'
|
||
{
|
||
return naam.replace(/[\x00-\x1F|\/|\\|\*|\%\<\>\"\:\;\?\|\+]+/g, "_"); // " syntax highlight correctie
|
||
},
|
||
|
||
UNC: function (filepath) // ADODB.Stream SaveToFile vereist backslash als flexfilespath naar een UNC-share wijst
|
||
{
|
||
return filepath.replace(/\//g, "\\");
|
||
},
|
||
// IE doet een beetje raar als er een puntkomma in de content-disposition filenaam zit, dan negeert hij de rest
|
||
// Een bestand test.exe;.txt wordt dan zo maar 'uitgevoerd'
|
||
// Een # in de naam gaat ook raar: IE9 vervangt die zelf al door een _ maar daar vertrouwen wij niet op
|
||
// We hebben er verder geen probleem mee dat ze geupload worden (en ze bestaan ook), anders was
|
||
// toevoegen aan safe.filename natuurlijk logischer.
|
||
ContentName: function(fname)
|
||
{
|
||
return safe.filename(fname).replace(/[\;\#]+/g, "_")
|
||
},
|
||
UserContext: function ()
|
||
{
|
||
try
|
||
{
|
||
var _oAbout = Server.CreateObject('SLNKDWF.About');
|
||
return "UserContext: " + _oAbout.UserContext;
|
||
}
|
||
catch (e)
|
||
{
|
||
return "UserContext: no SLNKDWF.About " + e.description;
|
||
}
|
||
}
|
||
}
|
||
|
||
function abort_with_warning(warning, code)
|
||
{
|
||
if (Request.QueryString("api2").Count > 0)
|
||
{
|
||
code = code || 500;
|
||
var data = { error: { code: code,
|
||
message: warning
|
||
}
|
||
};
|
||
if (code == 500)
|
||
__DoLog("abort_with_warning: " + warning); // komt namelijk niet in de AiAi
|
||
|
||
var format = Request.QueryString("format");
|
||
if (format == "xml")
|
||
{
|
||
Response.ContentType = "text/xml";
|
||
var xml_antwoord = api2_rest.json2xml([data.error], { records_name: "errors", record_name: "error"}, true);
|
||
Response.Write(xml_antwoord.xml);
|
||
}
|
||
else if (format == "html")
|
||
{
|
||
Response.ContentType = "text/html";
|
||
var str_antwoord = "<!DOCTYPE html><html><head></head><body><pre>"
|
||
+ Server.HTMLEncode(JSON.stringify(data, null, 2))
|
||
+ "</pre></body></html>";
|
||
Response.Write(str_antwoord);
|
||
}
|
||
else
|
||
{
|
||
Response.ContentType = "application/json";
|
||
Response.Write(JSON.stringify(data, null, 2));
|
||
}
|
||
var codestr = String(code);
|
||
if (typeof code == "number")
|
||
{
|
||
var codestr = { 400: "Bad request",
|
||
403: "Forbidden",
|
||
404: "Not Found",
|
||
422: "Unprocessable Entity" }[code];
|
||
if (codestr)
|
||
code = code + " " + codestr;
|
||
}
|
||
Response.Status = code;
|
||
Response.End;
|
||
}
|
||
else if (JSON_Result)
|
||
{
|
||
Response.Write(JSON.stringify({ warning: warning, keepForm: true }));
|
||
}
|
||
else
|
||
{
|
||
var pad = String(Request.ServerVariables("PATH_INFO"));
|
||
pad = pad.substring(rooturl.length+1).toLowerCase();
|
||
if (!pad || pad == "default.asp") // warning *gegenereerd* door de root-pagina
|
||
{ // is allemaal veel te complex
|
||
shared.simpel_page(warning);
|
||
}
|
||
else
|
||
{
|
||
%>
|
||
<html>
|
||
<head>
|
||
<% FCLTHeader.Generate() %>
|
||
<script>
|
||
$(function () {
|
||
FcltMgr.closeDetail(window, { warning: "<%=safe.jsstring(warning)%>",
|
||
keepForm: true
|
||
});
|
||
});
|
||
</script>
|
||
</head>
|
||
<body>
|
||
</body>
|
||
</html>
|
||
<%
|
||
}
|
||
}
|
||
ASPPAGE_END();
|
||
Response.End
|
||
}
|
||
|
||
var protectHMAC =
|
||
{
|
||
// Alleen geschikt als tijdelijk geheim, doorgaans wordt
|
||
// IIS elke nacht gerecycled en dan zijn we deze kwijt
|
||
getProtectSecret: function ()
|
||
{
|
||
var appsecret = Application(customerId + "_protectsecret");
|
||
if (typeof appsecret == "undefined")
|
||
{
|
||
appsecret = shared.random(32);
|
||
Application.Lock();
|
||
Application(customerId + "_protectsecret") = appsecret;
|
||
Application.UnLock();
|
||
}
|
||
return appsecret;
|
||
},
|
||
|
||
create: function(str, params)
|
||
{
|
||
params = params || {};
|
||
params.sleutel = params.sleutel || protectHMAC.getProtectSecret();
|
||
|
||
var tm = new Date();
|
||
// gedurende de dag krijg je dezelfde hmac.
|
||
// 'Ontvanger' moet wel protectQS.verify({ expire: 24*60 } ) doen, anders krijg je na 08:00 's ochtends hmac errors!
|
||
if (params.cacheablehmac)
|
||
var tm = tm.midnight();
|
||
|
||
var ts = String(Math.round(tm.getTime() / 1000));
|
||
var data = ts + ":" + str
|
||
__Log("hmacdata: " + data);
|
||
//__Log("sleutel: "+ params.sleutel);
|
||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
|
||
var sig = oCrypto.hex_hmac_sha1(params.sleutel, data);
|
||
var hmac = oCrypto.hex2base64(sig, false, true); // no padding, urlsafe
|
||
oCrypto = null; // Caching klinkt leuk maar Oracle sessies blijven langer hangen?
|
||
return ts+":"+hmac;
|
||
},
|
||
|
||
verify: function (str, hmac, params)
|
||
{
|
||
params = params || {};
|
||
params.expire = params.expire || 720;
|
||
var expTime = new Date();
|
||
expTime.setMinutes(expTime.getMinutes()-params.expire); // max expire in het verleden
|
||
var future = new Date;
|
||
future.setMinutes(future.getMinutes() + 3); // Over 3 minuten begint de toekomst :-)
|
||
// Voorkomt misbruik tijdens zomer/wintertijd wissel
|
||
|
||
/* Heel af en toe worden we aangeroepen met hmac=1746014556%253A2UgO8p... waarbij de ':' eerst
|
||
encoded is naar %3A en daarna de '%' ook nog weer naar '%25' wat tot %253A leidt in de IIS logging.
|
||
Dit zijn volgens mij (buggy) virusscanners die links in e-mails controleren. Het levert irritante foutmeldingen in de logging.
|
||
Deze specifieke 'foute' encoding daarom toch maar ondersteunen. Het wordt er niet onveiliger van.
|
||
*/
|
||
var cleanhmac = hmac.replace('%3A', ':');
|
||
var hmacArr = cleanhmac.split(":");
|
||
if (hmacArr.length != 2 ||
|
||
hmacArr[0].length != 10 || // 10 cijfers timestamp
|
||
hmacArr[1].length < 26 || // HMAC_SHA1 is 160bit --> 20 byte --> 20/3*4 is 26 of 27 base64 karakters
|
||
hmacArr[1].length > 27)
|
||
{
|
||
__DoLog("Bad HMAC syntax: {0}".format(hmac), "#ff0000");
|
||
shared.internal_error("Bad HMAC syntax"); // Net iets minder erg dan een AiAi
|
||
}
|
||
|
||
var createTimeInt = parseInt(hmacArr[0],10);
|
||
var createTime = new Date(createTimeInt*1000);
|
||
if (!createTimeInt || !createTime || createTime < expTime || createTime > future)
|
||
{
|
||
createTime.setMinutes(createTime.getMinutes() + params.expire);
|
||
__Log("HMAC: Te laat: je had voor {0} moeten zijn.".format(toISODateTimeString(createTime, true)));
|
||
if (params.relaxed)
|
||
return false;
|
||
else
|
||
{
|
||
shared.simpel_page(L("lcl_hmac_late"));
|
||
}
|
||
}
|
||
|
||
__Log("testing hmacdata: " + str);
|
||
params.sleutel = params.sleutel || protectHMAC.getProtectSecret();
|
||
//__Log("testing sleutel: "+ params.sleutel);
|
||
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
|
||
var sig = oCrypto.hex_hmac_sha1(params.sleutel, hmacArr[0] + ":" + str);
|
||
var should_hmac = oCrypto.hex2base64(sig, false, true); // no padding, urlsafe
|
||
oCrypto = null;
|
||
|
||
if (hmacArr[1] != should_hmac)
|
||
{
|
||
__Log("str: " + str);
|
||
__Log("hmac: " + hmac);
|
||
__Log("HMAC[1]: " + hmacArr[1]);
|
||
__Log("SHOULD: " + should_hmac);
|
||
if (params.relaxed)
|
||
{
|
||
__Log("(relaxed==true, will try hmac again with user_key==-1)");
|
||
return false;
|
||
}
|
||
else
|
||
INTERNAL_ERROR_HMAC_TAMPERING;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
var protectQS =
|
||
{
|
||
// Bescherm de url tegen tampering door een hmac achteraan toe te voegen
|
||
// Te controleren aan de ontvangende kant met protectQS.verify()
|
||
// PAS OP: protectQS.wsc bevat voor Facmgt nog (even) hetzelfde algoritme
|
||
create: function(url, params)
|
||
{
|
||
params = params || {};
|
||
|
||
var splitter = url.split("?");
|
||
var pad = splitter[0];
|
||
var qs = splitter.length>1?splitter[1]:"x=x";
|
||
var padsplitter = pad.split("/");
|
||
var file = padsplitter[padsplitter.length-1]; // laatste component
|
||
// Let op dat protectQS.wsc hetzelfde doet voor Facmgt
|
||
var data = (params.no_user_key?"":(user_key + ":")) + file.toUpperCase() + "?" + qs;
|
||
var hmacced = protectHMAC.create(data, params);
|
||
return pad + "?" + qs + "&hmac="+Server.URLencode(hmacced);
|
||
},
|
||
|
||
// params: expire: in minuten. Default 720, een heel kritische functie kan zichzelf scherper beschermen
|
||
// allowparams []: bijv. 'outputmode'. Deze worden er voor de HMAC berekening uitgestript
|
||
// relaxed: doe niet al te moeilijk over errors (maar wel false)
|
||
verify: function (params)
|
||
{
|
||
params = params || {};
|
||
|
||
if (params.relaxed && Request.QueryString("hmac").Count == 0)
|
||
return false;
|
||
|
||
// vanuit API2 geven we checkqs en checkpath mee omdat die door IIS Rewrite
|
||
// te veel veranderd zijn
|
||
var checkurl = params.checkqs || String(Request.QueryString);
|
||
|
||
if (params.allowparams)
|
||
{
|
||
var i;
|
||
for (i in params.allowparams)
|
||
{
|
||
var param = params.allowparams[i];
|
||
if (Request.QueryString(param).Count > 0)
|
||
{ // die rekenen we niet mee in de HMAC
|
||
checkurl = checkurl.replace(param + "=" + encodeURIComponent(Request.QueryString(param)) + "&", "");
|
||
checkurl = checkurl.replace("&" + param + "=" + encodeURIComponent(Request.QueryString(param)), "");
|
||
}
|
||
}
|
||
}
|
||
var hmac = getQParam("hmac");
|
||
var hmacArr = hmac.split(":");
|
||
var indexHmac = String(checkurl).indexOf("&hmac=");
|
||
|
||
if (checkurl.substring(indexHmac+1).indexOf("&") >=0)
|
||
{
|
||
if (params.relaxed)
|
||
return false;
|
||
else
|
||
{
|
||
__DoLog("HMAC url extension not allowed: {0}".format(checkurl), "#ff0000");
|
||
shared.internal_error("HMAC url extension not allowed"); // Net iets minder erg dan een AiAi
|
||
}
|
||
}
|
||
|
||
var qs = checkurl.substring(0,indexHmac);
|
||
|
||
var pad = params.checkpath || String(Request.ServerVariables("SCRIPT_NAME"));
|
||
var padsplitter = pad.split("/");
|
||
var file = padsplitter[padsplitter.length-1]; // laatste component
|
||
|
||
// Let op dat create dezelfde data hasht
|
||
var data = (params.no_user_key?"":(user_key + ":")) + file.toUpperCase() + "?" +qs;
|
||
//__Log("testing hmacdata: " + data);
|
||
//__Log("testing sleutel: "+ params.sleutel);
|
||
if (params.allow_anonymous)
|
||
params.relaxed = true;
|
||
var is_ok = protectHMAC.verify(data, getQParam("hmac"), params); // klapt er uit bij hmac-tampering en relaxed==false
|
||
if (!is_ok && params.allow_anonymous)
|
||
{ // Testen met user_key == -1
|
||
var data = "-1" + ":" + file.toUpperCase() + "?" +qs;
|
||
params.relaxed = false; // Nu moet hij echt kloppen
|
||
protectHMAC.verify(data, getQParam("hmac"), params);
|
||
}
|
||
return is_ok;
|
||
}
|
||
}
|
||
|
||
// http://www.owasp.org/index.php/Session_Fixation_Protection
|
||
function setASPFIXATION()
|
||
{
|
||
var FACSESSIONID = shared.random(32); // genereer grote random string.
|
||
var ASPFIXATION = Session("customerId") + FACSESSIONID;
|
||
Response.Cookies("ASPFIXATION") = ASPFIXATION; // deze controleren we weer in default.inc
|
||
Response.Cookies("ASPFIXATION").Path = rooturl + "/"; // anders niet met ServerXMLHttp
|
||
if (S("auto_https") & 2)
|
||
Response.Cookies("ASPFIXATION").Secure = true;
|
||
Session("RVT_TOKEN") = shared.random(32) + "_" + toISODateTimeString(new Date());
|
||
Session("ASPFIXATION") = ASPFIXATION; // deze controleren we weer in default.inc
|
||
Session("FACSESSIONID") = FACSESSIONID;
|
||
}
|
||
|
||
var protectRequest =
|
||
{
|
||
theToken: function () { return Session("RVT_TOKEN") }, // Session RVT_TOKEN wordt gebruikt als anti Cross-Site Request Forgery (CSRF)
|
||
theVar: "RVT_token",
|
||
inputToken: function (params) // Maak een hidden inputveld met token
|
||
{
|
||
params = params || {};
|
||
%>
|
||
<input name="<%=protectRequest.theVar%>" id="<%=(protectRequest.theVar + "_" + (new Date()).getTime())%>" type="hidden" value="<%=safe.htmlattr(protectRequest.theToken())%>"<%=(params.formid ? ' form="' + params.formid + '"' : '')%>>
|
||
<%
|
||
},
|
||
// Van dataToken is ook een clientside variant in iface.js
|
||
dataToken: function (dataName) // Voeg aan een data hash een input token toe
|
||
{ %>
|
||
<%=dataName%>.<%=protectRequest.theVar%> = "<%=safe.jsstring(protectRequest.theToken())%>";
|
||
<%
|
||
},
|
||
|
||
validateToken: function (externtoken)
|
||
{ // De token van het hidden inputveld valideren met de token van de cookie.
|
||
// Voorkeur gaat uit naar het gebruik van getFParam(), maar in Multipart/form-data zijn deze niet beschikbaar.
|
||
// De form-parameters worden in upload.inc alsnog uitgelezen, zodat het token aan deze functie meegegeven kan worden.
|
||
try // API's hebben vaak inputXML.load(Request); gedaan en dan werkt getFParam niet meer
|
||
{
|
||
var verificationToken = (externtoken ? externtoken : getFParam(protectRequest.theVar, ""));
|
||
}
|
||
catch (e)
|
||
{ // API's die buildInsert of buildUpdate doen moeten daar vaak { noValidateToken: true } bij doen
|
||
__DoLog("INTERNAL_ERROR_TOKEN_VALIDATIE", "#FFFF00");
|
||
INTERNAL_ERROR_TOKEN_VALIDATIE;
|
||
};
|
||
var cookieToken = protectRequest.theToken()||""; // is leeg bij self_register.asp als we nog niet zijn ingelogd.
|
||
|
||
if (verificationToken != cookieToken)
|
||
{ // Is deze functie vanuit een post aangeroepen? Dan afhandeling door post functie af laten handelen.
|
||
|
||
var message = L("lcl_authentication_error") + "\n" + toISODateTimeString(new Date());
|
||
message += "\n(" + verificationToken.substring(verificationToken.length-19) + "==>" + cookieToken.substring(cookieToken.length-19) + ")";
|
||
if (typeof DOCTYPE_Disable != "undefined" && DOCTYPE_Disable == 1)
|
||
{
|
||
var result = {message: message };
|
||
Response.Write(JSON.stringify(result));
|
||
Response.End;
|
||
}
|
||
else
|
||
{
|
||
abort_with_warning(message);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
var cache = {
|
||
whenTrue: function _whenTrue(b)
|
||
{
|
||
if (b)
|
||
{
|
||
var eTag = '"' + user.lang() + "_" + S("cache_changecounter") + "_" + Session("ASPFIXATION") + '"'; // Hoogstens zo lang je ingelogd bent
|
||
Response.AddHeader("ETag", eTag);
|
||
Response.AddHeader("Last-Modified", new Date().toGMTString());
|
||
Response.CacheControl = "private";
|
||
if (Request.ServerVariables("HTTP_IF_NONE_MATCH") == eTag)
|
||
{ // We hebben een match!
|
||
var tm = "";
|
||
if (Request.ServerVariables("HTTP_IF_MODIFIED_SINCE").Count)
|
||
tm = " (" + toISODateTimeString(new Date(Request.ServerVariables("HTTP_IF_MODIFIED_SINCE")), true) + ")";
|
||
__Log("Geslaagde caching" + tm + ": we geven status 304 terug en stoppen.");
|
||
Response.Clear();
|
||
Response.Status = "304 Not modified";
|
||
Response.End;
|
||
}
|
||
}
|
||
},
|
||
|
||
whenNoRecords: function _whenNorecords(sql)
|
||
{
|
||
var oRs = Oracle.Execute(sql);
|
||
this.whenTrue(oRs.Eof);
|
||
oRs.Close();
|
||
}
|
||
}
|
||
// Datum functies
|
||
Date.prototype.toSQL = function toSQL(withTime, withSeconds)
|
||
{
|
||
var year = this.getFullYear();
|
||
if (year < 1000 || year > 9999)
|
||
shared.internal_error("Invalid year " + this.toLocaleString()); // Net iets minder erg dan ORA-01830
|
||
|
||
var str = padout(this.getDate()) + "-" + padout(this.getMonth() + 1) + "-" + padout(this.getFullYear())
|
||
var dateformat = "DD-MM-YYYY";
|
||
if (withTime)
|
||
{
|
||
str += " " + padout(this.getHours()) + ":" + padout(this.getMinutes());
|
||
dateformat += " HH24:MI";
|
||
if (withSeconds)
|
||
{
|
||
str += ":" + padout(this.getSeconds());
|
||
dateformat += ":SS";
|
||
}
|
||
}
|
||
return "to_date(" + safe.quoted_sql(str) + ", '" + dateformat + "')";
|
||
}
|
||
// Als de Date al een server-datetime is, hoeven we geen time-zone conversie uit te voeren
|
||
Date.prototype.beginToSQL = function beginToSQL(dateOnly, isServerTimeZone)
|
||
{
|
||
var theDateStart = new Date(this);
|
||
if (isServerTimeZone) {
|
||
return new Date(theDateStart.setHours(0, 0)).toSQL(!dateOnly);
|
||
} else {
|
||
theDateStart = new Date(convertToLocalTime(theDateStart).setHours(0, 0));
|
||
return convertToServerTime(theDateStart).toSQL(!dateOnly);
|
||
}
|
||
}
|
||
// Als de Date al een server-datetime is, hoeven we geen time-zone conversie uit te voeren
|
||
Date.prototype.endToSQL = function endToSQL(dateOnly, isServerTimeZone)
|
||
{
|
||
var theDateEnd = new Date(this);
|
||
if (isServerTimeZone) {
|
||
return new Date(theDateEnd.setHours(23, 59)).toSQL(!dateOnly);
|
||
} else {
|
||
theDateEnd = new Date(convertToLocalTime(theDateEnd).setHours(23, 59));
|
||
return convertToServerTime(theDateEnd).toSQL(!dateOnly);
|
||
}
|
||
}
|
||
|
||
Date.prototype.midnight = function midnight()
|
||
{
|
||
var midn = new Date(this);
|
||
midn.setHours(0,0,0,0);
|
||
return midn;
|
||
}
|
||
|
||
function inArray(needle, haystack) {
|
||
var length = haystack.length;
|
||
for(var i = 0; i < length; i++) {
|
||
if (haystack[i] == needle) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function isEmptyObject(obj) {
|
||
for (var prop in obj) {
|
||
if (obj.hasOwnProperty(prop)) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
function sharedTrim(str) { return str.replace(/^\s+|\s+$/g,""); }
|
||
|
||
function sharedIndexOf(needle, haystack) {
|
||
if (haystack == null || needle == null)
|
||
return -1;
|
||
for(var i = 0; i < haystack.length; i++) {
|
||
if (haystack[i] == needle) return i;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
function sortArray(data_arr, sortcolumn_arr)
|
||
{
|
||
// EXAMPLE:
|
||
// var fruits = [ {fruit:"Banana", qty: 2, color: "yellow"}
|
||
// , {fruit:"Orange", qty: 4, color: "orange"}
|
||
// , {fruit:"Apple" , qty: 3, color: "green"}
|
||
// , {fruit:"Apple" , qty: 5, color: "red"}
|
||
// , {fruit:"Mango" , qty: 1, color: "purple"}
|
||
// ];
|
||
// var sf = sortArray(fruits, ["fruit desc "," color asc"]);
|
||
// var sf = sortArray(fruits, ["qty desc"]);
|
||
// var sf = sortArray(fruits, ["color"]);
|
||
|
||
function _compare(sc, so)
|
||
{
|
||
return function (a,b)
|
||
{
|
||
var result = ( a[sc] < b[sc] ? -1 : (a[sc] > b[sc] ? 1 : 0) );
|
||
return result * so;
|
||
}
|
||
}
|
||
function _get_filters(sortstring)
|
||
{
|
||
var result = [];
|
||
var arr = sortstring.split(" ");
|
||
for (var i=0; i<arr.length; i++)
|
||
{
|
||
if (arr[i] != "")
|
||
result.push(arr[i]);
|
||
}
|
||
if (result.length == 1)
|
||
result.push(1); // default ASC
|
||
else if (result.length == 2)
|
||
result[1] = (result[1].toUpperCase().replace(/\s+/g,"") == "DESC" ? -1 : 1);
|
||
|
||
return result;
|
||
}
|
||
|
||
if (data_arr && sortcolumn_arr)
|
||
{
|
||
for (var i=sortcolumn_arr.length-1; i>=0; i--)
|
||
{
|
||
var sc_arr = _get_filters(sortcolumn_arr[i]);
|
||
data_arr.sort(_compare(sc_arr[0],sc_arr[1]));
|
||
}
|
||
}
|
||
return data_arr;
|
||
}
|
||
|
||
// Bepaalt de customerId (en rooturl)
|
||
// Na afloop is de globale variabele customerId gezet en opgeslagen in Session("customerId")
|
||
function determineCustomerId()
|
||
{
|
||
var validCustId = /[A-Z0-9]/;
|
||
// autodetect rooturl. Al onze pagina's beginnen met /cust of met /appl
|
||
var pad = String(Request.ServerVariables("PATH_INFO"));
|
||
var lowerpad = pad.toLowerCase();
|
||
var i1 = lowerpad.indexOf("/cust/");
|
||
if (i1 < 0)
|
||
i1 = lowerpad.indexOf("/appl/");
|
||
if (i1 < 0)
|
||
i1 = lowerpad.indexOf("/default.asp"); // API's
|
||
/* global */ rooturl = pad.substr(0, i1);
|
||
|
||
var trycust = "";
|
||
if ( typeof Session("customerId") == "undefined" ) // ASP-Sessie verlopen of nieuw binnen.
|
||
{
|
||
if (Request.QueryString("api").Count>0)
|
||
{
|
||
Session.Abandon(); // Voorkom dat een session ontstaat doordat we een API-call doen.
|
||
// When the Abandon method is called, the current Session object is queued for deletion
|
||
// but is not actually deleted until all of the script commands on the current page have
|
||
// been processed. This means that you can access variables stored in the Session object
|
||
// on the same page as the call to the Abandon method but not in any subsequent Web pages.
|
||
}
|
||
|
||
// is var customerId al gezet door /default.asp?
|
||
if (typeof customerId != 'undefined' && customerId != "XXXX")
|
||
trycust = customerId.toUpperCase();
|
||
else if (String(Request.Cookies("fcltcust"))) // Remember me knop
|
||
trycust = String(Request.Cookies("fcltcust"));
|
||
else
|
||
{ // URL formaat http://xxxx.5iwork/facilitor5iwork: pak eerste 4 letters
|
||
var host = String(Request.ServerVariables("HTTP_HOST"));
|
||
trycust = host.substring(0,4).toUpperCase();
|
||
var fso = Server.CreateObject("Scripting.FileSystemObject");
|
||
if (!fso.FileExists(Server.MapPath(rooturl + "/cust/" + trycust + "/Oracle.udl")))
|
||
{
|
||
trycust = host.split(".")[0].toUpperCase(); // Misschien hele prefix (C2930)
|
||
if (!fso.FileExists(Server.MapPath(rooturl + "/cust/" + trycust + "/Oracle.udl")))
|
||
trycust = null;
|
||
}
|
||
}
|
||
// TODO: is er maar <20><>n cust-folder met een Oracle.udl? Gebruik die
|
||
}
|
||
|
||
// Deze overruled alles:
|
||
if (getQParamSafe("fac_id","") != "")
|
||
var trycust = getQParamSafe("fac_id").toUpperCase();
|
||
|
||
if (trycust && validCustId.test(trycust)) // Geen vreemde karakters en er is een udl?
|
||
{
|
||
var fso = Server.CreateObject("Scripting.FileSystemObject");
|
||
if (fso.FileExists(Server.MapPath(rooturl + "/cust/" + trycust + "/Oracle.udl")))
|
||
Session("customerId") = trycust;
|
||
else
|
||
{
|
||
Response.write("Invalid customerId: " + trycust);
|
||
Response.end;
|
||
}
|
||
}
|
||
|
||
/* global */ customerId = Session("customerId");
|
||
|
||
if (typeof customerId == "undefined")// Ik geef het op.
|
||
{
|
||
if (String(Request.ServerVariables("HTTP_ACCEPT")).match(/application\/json/) != null)
|
||
{
|
||
var msg = "Your session has expired.\nPlease restart Facilitor."; // L("xxx") vertrouw ik ook niet meer
|
||
Response.Write("FCLTExpired:" + msg); // FCLTExpired wordt zo opgepikt door FcltJquery.js ajaxSetup error handler
|
||
Response.End;
|
||
}
|
||
Response.Redirect(rooturl + "/appl/shared/expired.asp");
|
||
}
|
||
|
||
if (!validCustId.test(customerId)) // paranoia
|
||
{
|
||
INTERNAL_ERROR_BAD_CUSTOMERID;
|
||
}
|
||
}
|
||
|
||
function getFileOwner(fullpath)
|
||
{
|
||
try {
|
||
var oAbout = new ActiveXObject("SLNKDWF.About");
|
||
if (oAbout.VersionString >= "4,21")
|
||
var owner = oAbout.FileOwner(fullpath);
|
||
else
|
||
var owner = "*unknown*";
|
||
}
|
||
catch (e)
|
||
{
|
||
var owner = "*unknown*\n" + e.description;
|
||
}
|
||
return owner;
|
||
}
|
||
function getUserContext()
|
||
{
|
||
try {
|
||
var oAbout = new ActiveXObject("SLNKDWF.About");
|
||
return oAbout.UserContext;
|
||
}
|
||
catch (e)
|
||
{
|
||
return "*unknown*\n" + e.description;
|
||
}
|
||
}
|
||
|
||
|
||
function getCustXsl(prefix)
|
||
{
|
||
prefix = prefix || "";
|
||
return custpath + "/xsl/" + prefix + customerId + ".xsl";
|
||
}
|
||
|
||
function getCustCss(prefix)
|
||
{
|
||
prefix = prefix || "";
|
||
var fso = Server.CreateObject("Scripting.FileSystemObject");
|
||
var cssFile = custpath + "/" + prefix + customerId + "_deprecated.css";
|
||
if (!fso.FileExists(Server.MapPath(cssFile)))
|
||
cssFile = custpath + "/" + prefix + "cust_deprecated.css";
|
||
return cssFile;
|
||
}
|
||
|
||
// Er is een onvoorziene fout opgetreden
|
||
// Dat loggen we in de reguliere logfile en vervolgens forceren we met een throw die we
|
||
// niet catchen dat er een http-500 error optreedt die we dan weer afvangen in 500_error.asp
|
||
function _AiAi(txt)
|
||
{
|
||
if (typeof theLogger != "undefined") // Bijvoorbeeld met http://logc.lokalhost/trunk/appl/fac/fac_report.asp?outputmode=1&mode=yvf...
|
||
__DoLog("AiAi: " + txt, '#f00');
|
||
Session("last_caller") = __callerTekst(_AiAi.caller); // worden door 500-error.asp opgepikt
|
||
Session("last_aiai") = txt;
|
||
if (typeof THIS_FILE == "string")
|
||
Session("THIS_FILE") = THIS_FILE;
|
||
throw(txt);
|
||
}
|
||
|
||
// Usage in function mld.func_enabled_melding
|
||
// _DetectMultipleCalls("mld.func_enabled_melding", pmld_melding_key);
|
||
var _multicall = {};
|
||
function _DetectMultipleCalls(marker, key)
|
||
{
|
||
if (marker in _multicall)
|
||
{
|
||
if (_multicall[marker][key])
|
||
{
|
||
_multicall[marker][key] ++;
|
||
__Log("{0} was called multiple ({1}) times with key {2} in this asp, inefficient!".format(marker, _multicall[marker][key], key), "#FF0080");
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_multicall[marker] = {};
|
||
}
|
||
_multicall[marker][key] = 1;
|
||
}
|
||
|
||
// pcontentdp kan "none" zijn, dan 'downloaden" we gewoon
|
||
function StreamFile(filePath, filename, params)
|
||
{
|
||
params = params || {};
|
||
var safefullpath = filePath + "/" + safe.filename(filename);
|
||
|
||
var zipit = getQParamInt("zipfile", 0) == 1;
|
||
if (!zipit)
|
||
{
|
||
var autozipfile = getQParamInt("autozipfile", -1); // Als meer dan xx kB dan zippen
|
||
if (autozipfile > 0)
|
||
{
|
||
var sz = getFilesize(safefullpath);
|
||
if (sz >= autozipfile * 1024)
|
||
{
|
||
zipit = true;
|
||
}
|
||
}
|
||
}
|
||
if (zipit)
|
||
{
|
||
if (params.mime == "text/html") // Handig voor logfiles
|
||
filename = filename.replace(/\.html\.log$/, ".html");
|
||
zipfile(safefullpath, filename);
|
||
}
|
||
params.pcontentdp = params.pcontentdp || "attachment";
|
||
try
|
||
{
|
||
if (!fso.FileExists(safefullpath))
|
||
{
|
||
shared.simpel_page(L("lcl_flex_filenotfoundRO"));
|
||
}
|
||
Response.Clear;
|
||
Response.Buffer = false; // Geen buffering nodig. Bovendien kunnen we nu ook bestanden
|
||
// groter dan de ResponseBuffersize aan
|
||
// Known problems:
|
||
// "Plus+Quote'Spatie Rare<72>&.txt" non-ASCII karakters in pFilename worden wel eens onbedoeld herkend als UTF8
|
||
if (params.pcontentdp == "none")
|
||
{
|
||
if (!params.mime)
|
||
{
|
||
var extension = filename.split(".").pop().toLowerCase();
|
||
params.mime = S("flex_mimetypes")[extension] || "application/octet-stream";
|
||
}
|
||
}
|
||
else
|
||
Response.AddHeader("content-disposition", params.pcontentdp + "; filename= \"" + safe.ContentName(filename) + "\"");
|
||
|
||
Response.contenttype = params.mime;
|
||
|
||
// An ASP application uses internal server buffers when writing data to the client,
|
||
// irrespective of the value of Response.Buffer. As the application is writing data
|
||
// synchronously, the data buffer can be reused when the BinaryWrite function returns,
|
||
// while the server is writing the data asynchronously to the client. The server,
|
||
// in turn, makes a copy of the data into its internal buffers. As a result of
|
||
// this buffering, the ASP application should not try to send unreasonable amounts
|
||
// of data in a single BinaryWrite, but rather break it into fragments so as to
|
||
// avoid running out of buffer space. Should the buffer space be exceeded,
|
||
// ASP error 251, "response exceeds the buffer limit," will be returned.
|
||
// While the default maximum buffer size is 4MB, the server administrator may increase it.
|
||
// Dan lijkt me 1MB aardig
|
||
var CHUNKSIZE = 1024*1024;
|
||
|
||
// fso kan ook locked-for-write files (zoals Shibboleth logfiles) aan
|
||
// .log files veronderstellen we gewoon altijd ASCII
|
||
if (filename.match(/\.log$/i) && safefullpath.match(/shibboleth-sp/i))
|
||
{
|
||
Response.contenttype = "text/plain";
|
||
var f = fso.OpenTextFile(safefullpath, 1, false, -1); // ForReading/no create/Unicode(?)
|
||
while (!f.AtEndOfStream && Response.IsClientConnected)
|
||
{
|
||
Response.BinaryWrite(f.read(CHUNKSIZE));
|
||
}
|
||
Response.End;
|
||
}
|
||
// Anders gebruiken we toch maar liever de ADODB stream
|
||
var oStream = Server.CreateObject("ADODB.Stream");
|
||
oStream.Open;
|
||
oStream.Type = 1; // adTypeBinary
|
||
oStream.LoadFromFile(safe.UNC(safefullpath));
|
||
while (!oStream.EOS && Response.IsClientConnected)
|
||
{
|
||
Response.BinaryWrite(oStream.read(CHUNKSIZE));
|
||
}
|
||
if (params.deletefile)
|
||
{
|
||
fso.DeleteFile(safe.UNC(safefullpath));
|
||
}
|
||
// Kan dit hier? ASPPAGE_END();
|
||
|
||
Response.End();
|
||
}
|
||
catch(e)
|
||
{
|
||
__DoLog(Server.HTMLEncode(filename) + "\n" + e.description + "\n" + filePath, "#f00");
|
||
Response.Write(Server.HTMLEncode(filename) + "<p></p>" + e.description);
|
||
}
|
||
oStream = null;
|
||
}
|
||
|
||
|
||
// Merk op dat we een beetje browser capabilities en device capabilities
|
||
// op <20><>n hoop gooien. Goed genoeg vooralsnog
|
||
device =
|
||
{ // lower 8 bits
|
||
isSupported: 0x0001,
|
||
isDesktop : 0x0002,
|
||
isTouch : 0x0004,
|
||
isMobile : 0x0008,
|
||
// next 8 bits
|
||
canPrint : 0x0100, // Show print buttons
|
||
canExcel : 0x0200, // Show Excel buttons
|
||
canUpload : 0x0400, // Can upload files
|
||
canDownload: 0x0800, // Can download files
|
||
// more
|
||
|
||
_devicebits: 0xff01, // Default desktop, alle capabilities
|
||
|
||
init: function ()
|
||
{
|
||
if (typeof Session("devicebits") != "undefined")
|
||
this._devicebits = Session("devicebits")
|
||
else
|
||
Session("devicebits") = this._devicebits;
|
||
},
|
||
test: function (bits)
|
||
{
|
||
return ( (this._devicebits & bits) == bits);
|
||
},
|
||
testAll: function (bits)
|
||
{
|
||
return test(bits);
|
||
},
|
||
testAny: function (bits)
|
||
{
|
||
return ( (this._devicebits & bits) != 0);
|
||
},
|
||
set: function (bits, newval)
|
||
{
|
||
if (newval || typeof newval == "undefined")
|
||
this._devicebits = this._devicebits | bits;
|
||
else // reset
|
||
this._devicebits = this._devicebits & (~bits);
|
||
Session("devicebits") = this._devicebits;
|
||
},
|
||
isapp: function ()
|
||
{
|
||
return Session("aut_client_key") > 0;
|
||
}
|
||
}
|
||
|
||
myJSON =
|
||
{
|
||
internal_parsedate: function (key, value)
|
||
{
|
||
var a;
|
||
if (typeof value === 'string') {
|
||
a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||
if (a) {
|
||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
|
||
}
|
||
}
|
||
return value;
|
||
},
|
||
// myJSON.parse doet hetzelfde als JSON.parse maar herkent automatisch datum variabelen
|
||
parse: function _parse(text)
|
||
{
|
||
return JSON.parse(text, myJSON.internal_parsedate);
|
||
}
|
||
}
|
||
|
||
HTTP =
|
||
{ // params: type, data, headers, APIKEY (voor API2)
|
||
getJSON: function _getJSON(url, params) // Serverside variant van jQuery $.getJSON
|
||
{
|
||
params = params || {};
|
||
if (!params.type)
|
||
params.type = params.data?"POST":"GET"; // Met data default POST, zonder data default GET
|
||
|
||
var http_request = Server.CreateObject("WinHTTP.WinHTTPRequest.5.1");
|
||
|
||
var vraag = JSON.stringify(params.data, null);
|
||
__Log("HTTP url: " + url);
|
||
if (vraag)
|
||
__Log("data: " + vraag);
|
||
http_request.open(params.type, url, false); // Synchroon
|
||
// Het volgende lijkt weinig effect te hebben, post-body is nog steeds utf-8?
|
||
// in api.inc/RequestJSON verwachten we dan ook maar utf-8 dus netto werkt het goed?
|
||
http_request.setRequestHeader("Content-Type", "application/json; charset=windows-1252");
|
||
if (params.APIKEY)
|
||
http_request.setRequestHeader("X-FACILITOR-API-Key", params.APIKEY);
|
||
for ( var i in params.headers )
|
||
{
|
||
http_request.setRequestHeader(i, params.headers[ i ]);
|
||
}
|
||
// Het mag niet te lang duren!
|
||
var lResolve = 5 * 1000;
|
||
var lConnect = 5 * 1000;
|
||
var lSend = 15 * 1000;
|
||
var lReceive = 15 * 1000;
|
||
http_request.setTimeouts(lResolve, lConnect, lSend, lReceive);
|
||
var errtxt = "";
|
||
var errnum = 0;
|
||
try
|
||
{
|
||
http_request.send(vraag);
|
||
}
|
||
catch (e)
|
||
{
|
||
errtxt = e.description;
|
||
errnum = e.number;
|
||
}
|
||
if (!errtxt && http_request.status != 200)
|
||
{
|
||
// Hier HTML lijkt me misplaatst
|
||
errtxt = "HTTP status " + http_request.status
|
||
+ ": " + http_request.responseText;
|
||
}
|
||
if (errtxt)
|
||
{
|
||
//__DoLog(" url: " + url, "#FF0000");
|
||
//__DoLog(" data: " + vraag);
|
||
if (errnum == -2147012894) // "The operation timed out", dan is http_request niet te benaderen
|
||
__DoLog(" http_request {0} mislukt: {1}".format(url, errtxt), "#FF0000");
|
||
else if (http_request.status == 404)
|
||
__Log(" http_request status = 404 {0}".format(url));
|
||
else if (http_request.status == 401)
|
||
__DoLog(" http_request status = 401 {0}".format(url));
|
||
else
|
||
__DoLog(" http_request {0} mislukt: {1}".format(url, errtxt), "#FF0000");
|
||
}
|
||
else
|
||
{
|
||
__Log(http_request.ResponseText);
|
||
try
|
||
{
|
||
var result = myJSON.parse(http_request.ResponseText)
|
||
}
|
||
catch (e)
|
||
{
|
||
__DoLog("Parse error: " + e.message);
|
||
__DoLog(http_request.ResponseText);
|
||
result = { success: false, message: e.message };
|
||
}
|
||
return result;
|
||
}
|
||
},
|
||
urlzelf: function ()
|
||
{
|
||
return HTTP.urlzelfnoroot() + rooturl;
|
||
},
|
||
urlzelfnoroot: function ()
|
||
{
|
||
var proto = (Request.ServerVariables("SERVER_PORT") == "443")? "https" : "http";
|
||
var sitenoroot = proto + "://" + Request.ServerVariables("SERVER_NAME");
|
||
return sitenoroot;
|
||
}
|
||
}
|
||
|
||
// Alleen nog maar ipv4
|
||
// http://stackoverflow.com/a/503238/569090
|
||
IP =
|
||
{
|
||
isIPv4: function(IPaddress)
|
||
{
|
||
return String(IPaddress).indexOf(".") > -1;
|
||
},
|
||
isIPv6: function(IPaddress)
|
||
{
|
||
return String(IPaddress).indexOf(":") > -1;
|
||
},
|
||
IPnumber: function(IPaddress) {
|
||
var ip = IPaddress.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
|
||
if(ip) {
|
||
return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4]);
|
||
}
|
||
// else ... ?
|
||
__DoLog("Invalid IPAddress: " + IPaddress);
|
||
INTERNAL_ERROR_INVALID_IP;
|
||
},
|
||
|
||
IPmask: function (maskSize) {
|
||
return -1<<(32-maskSize)
|
||
},
|
||
|
||
inSubnet: function(ip, subnet)
|
||
{
|
||
var long_ip = IP.IPnumber(ip);
|
||
var bits = 32;
|
||
if (subnet.indexOf("/") > 0)
|
||
{
|
||
bits = parseInt(subnet.split("/")[1], 10);
|
||
subnet = subnet.split("/")[0];
|
||
}
|
||
if (bits == 0) // extra omdat IPmask(0) een overflow geeft
|
||
return true;
|
||
var mask = IP.IPmask(bits);
|
||
var long_subnet = IP.IPnumber(subnet);
|
||
|
||
return (long_ip & mask) == (long_subnet & mask);
|
||
},
|
||
|
||
// subnets gescheiden door komma's
|
||
inAnySubnet: function(ip, subnets)
|
||
{
|
||
if (!subnets)
|
||
INTERNAL_ERROR_NOSUBNETS; // 'k weet niet of default veilig of onveilig gewenst is
|
||
var arr = String(subnets).split(",");
|
||
for (var i = 0; i < arr.length; i++)
|
||
{
|
||
if (IP.inSubnet(ip, arr[i]))
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
}
|
||
%>
|