public string wmGetMergedParameterXML(string sType, string sID, string sEcosystemID) { dataAccess dc = new dataAccess(); acUI.acUI ui = new acUI.acUI(); taskMethods tm = new taskMethods(); FunctionTemplates.HTMLTemplates ft = new FunctionTemplates.HTMLTemplates(); if (string.IsNullOrEmpty(sID)) throw new Exception("ID required to look up default Parameter values."); string sErr = ""; //what is the task associated with this action? //and get the XML for it string sSQL = ""; string sDefaultsXML = ""; string sTaskID = ""; if (sType == "action") { sDefaultsXML = tm.wmGetObjectParameterXML(sType, sID, ""); sSQL = "select t.task_id" + " from ecotemplate_action ea" + " join task t on ea.original_task_id = t.original_task_id" + " and t.default_version = 1" + " where ea.action_id = '" + sID + "'"; } else if (sType == "instance") { sDefaultsXML = tm.wmGetObjectParameterXML(sType, sID, sEcosystemID); //IMPORTANT!!! if the ID is not a guid, it's a specific instance ID, and we'll need to get the task_id //but if it is a GUID, but the type is "instance", taht means the most recent INSTANCE for this TASK_ID if (ui.IsGUID(sID)) sTaskID = sID; else sSQL = "select task_id" + " from task_instance" + " where task_instance = '" + sID + "'"; } else if (sType == "plan") { sDefaultsXML = tm.wmGetObjectParameterXML(sType, sID, ""); sSQL = "select task_id" + " from action_plan" + " where plan_id = '" + sID + "'"; } else if (sType == "schedule") { sDefaultsXML = tm.wmGetObjectParameterXML(sType, sID, ""); sSQL = "select task_id" + " from action_schedule" + " where schedule_id = '" + sID + "'"; } //if we didn't get a task id directly, use the SQL to look it up if (string.IsNullOrEmpty(sTaskID)) if (!dc.sqlGetSingleString(ref sTaskID, sSQL, ref sErr)) throw new Exception(sErr); if (!ui.IsGUID(sTaskID)) throw new Exception("Unable to find Task ID for record."); XDocument xTPDoc = new XDocument(); XDocument xDefDoc = new XDocument(); //get the parameter XML from the TASK string sTaskParamXML = tm.wmGetParameterXML("task", sTaskID, ""); if (!string.IsNullOrEmpty(sTaskParamXML)) { xTPDoc = XDocument.Parse(sTaskParamXML); if (xTPDoc == null) throw new Exception("Task Parameter XML data is invalid."); XElement xTPParams = xTPDoc.XPathSelectElement("/parameters"); if (xTPParams == null) throw new Exception("Task Parameter XML data does not contain 'parameters' root node."); } //we populated this up above too if (!string.IsNullOrEmpty(sDefaultsXML)) { xDefDoc = XDocument.Parse(sDefaultsXML); if (xDefDoc == null) throw new Exception("Defaults XML data is invalid."); XElement xDefParams = xDefDoc.XPathSelectElement("/parameters"); if (xDefParams == null) throw new Exception("Defaults XML data does not contain 'parameters' root node."); } //spin the nodes in the DEFAULTS xml, then dig in to the task XML and UPDATE the value if found. //(if the node no longer exists, delete the node from the defaults xml IF IT WAS AN ACTION) //and default "values" take precedence over task values. foreach (XElement xDefault in xDefDoc.XPathSelectElements("//parameter")) { //nothing to do if it's empty if (xDefault == null) break; //look it up in the task param xml XElement xDefName = xDefault.XPathSelectElement("name"); string sDefName = (xDefName == null ? "" : xDefName.Value); XElement xDefValues = xDefault.XPathSelectElement("values"); //nothing to do if there is no values node... if (xDefValues == null) break; //or if it contains no values. if (!xDefValues.HasElements) break; //or if there is no parameter name if (string.IsNullOrEmpty(sDefName)) break; //so, we have some valid data in the defaults xml... let's merge! //we have the name of the parameter... go find it in the TASK param XML XElement xTaskParam = xTPDoc.XPathSelectElement("//parameter/name[. = '" + sDefName + "']/.."); //NOTE! the /.. gets the parent of the name node! //if it doesn't exist in the task params, remove it from this document, permanently //but only for action types... instance data is historical and can't be munged if (xTaskParam == null && sType == "action") { ft.RemoveNodeFromXMLColumn("ecotemplate_action", "parameter_defaults", "action_id = '" + sID + "'", "//parameter/name[. = '" + sDefName + "']/.."); continue; } //is this an encrypted parameter? string sEncrypt = ""; if (xTaskParam.Attribute("encrypt") != null) sEncrypt = xTaskParam.Attribute("encrypt").Value; //and the "values" collection will be the 'next' node XElement xTaskParamValues = xTaskParam.XPathSelectElement("values"); string sPresentAs = xTaskParamValues.Attribute("present_as").Value; if (sPresentAs == "dropdown") { //dropdowns get a "selected" indicator string sValueToSelect = xDefValues.XPathSelectElement("value").Value; //find the right one by value and give it the "selected" attribute. XElement xVal = xTaskParamValues.XPathSelectElement("value[. = '" + sValueToSelect + "']"); if (xVal != null) xVal.SetAttributeValue("selected", "true"); } else if (sPresentAs == "list") { //first, a list gets ALL the values replaced... xTaskParamValues.ReplaceNodes(xDefValues); } else { //IMPORTANT NOTE: //remember... both these XML documents came from wmGetObjectParameterXML... //so any encrypted data IS ALREADY OBFUSCATED and base64'd in the oev attribute. //it's a single value, so just replace it with the default. XElement xVal = xTaskParamValues.XPathSelectElement("value[1]"); if (xVal != null) { //if this is an encrypted parameter, we'll be replacing (if a default exists) the oev attribute //AND the value... don't want them to get out of sync! if (dc.IsTrue(sEncrypt)) { if (xDefValues.XPathSelectElement("value") != null) if (xDefValues.XPathSelectElement("value").Attribute("oev") != null) { xVal.SetAttributeValue("oev", xDefValues.XPathSelectElement("value").Attribute("oev").Value); xVal.Value = xDefValues.XPathSelectElement("value").Value; } } else { //not encrypted, just replace the value. if (xDefValues.XPathSelectElement("value") != null) xVal.Value = xDefValues.XPathSelectElement("value").Value; } } } } return xTPDoc.ToString(SaveOptions.DisableFormatting); ; }
public void wmSaveActionParameterXML(string sActionID, string sActionDefaultsXML) { dataAccess dc = new dataAccess(); acUI.acUI ui = new acUI.acUI(); taskMethods tm = new taskMethods(); try { string sUserID = ui.GetSessionUserID(); if (ui.IsGUID(sActionID) && ui.IsGUID(sUserID)) { string sErr = ""; string sSQL = ""; //we encoded this in javascript before the ajax call. //the safest way to unencode it is to use the same javascript lib. //(sometimes the javascript and .net libs don't translate exactly, google it.) sActionDefaultsXML = ui.unpackJSON(sActionDefaultsXML); //we gotta peek into the XML and encrypt any newly keyed values PrepareAndEncryptParameterXML(ref sActionDefaultsXML); //so, like when we read it, we gotta spin and compare, and build an XML that only represents *changes* //to the defaults on the task. //what is the task associated with this action? sSQL = "select t.task_id" + " from ecotemplate_action ea" + " join task t on ea.original_task_id = t.original_task_id" + " and t.default_version = 1" + " where ea.action_id = '" + sActionID + "'"; string sTaskID = ""; if (!dc.sqlGetSingleString(ref sTaskID, sSQL, ref sErr)) throw new Exception(sErr); if (!ui.IsGUID(sTaskID)) throw new Exception("Unable to find Task ID for Action."); string sOverrideXML = ""; XDocument xTPDoc = new XDocument(); XDocument xADDoc = new XDocument(); //get the parameter XML from the TASK string sTaskParamXML = tm.wmGetParameterXML("task", sTaskID, ""); if (!string.IsNullOrEmpty(sTaskParamXML)) { xTPDoc = XDocument.Parse(sTaskParamXML); if (xTPDoc == null) throw new Exception("Task Parameter XML data is invalid."); XElement xTPParams = xTPDoc.XPathSelectElement("/parameters"); if (xTPParams == null) throw new Exception("Task Parameter XML data does not contain 'parameters' root node."); } //we had the ACTION defaults handed to us if (!string.IsNullOrEmpty(sActionDefaultsXML)) { xADDoc = XDocument.Parse(sActionDefaultsXML); if (xADDoc == null) throw new Exception("Action Defaults XML data is invalid."); XElement xADParams = xADDoc.XPathSelectElement("/parameters"); if (xADParams == null) throw new Exception("Action Defaults XML data does not contain 'parameters' root node."); } //spin the nodes in the ACTION xml, then dig in to the task XML and UPDATE the value if found. //(if the node no longer exists, delete the node from the action XML) //and action "values" take precedence over task values. //this does a regular loop because we can't remove from an IEnumerable int x = xADDoc.XPathSelectElements("//parameter").Count(); for (int i = (x-1); i>=0; i--) { XElement xDefault = xADDoc.XPathSelectElements("//parameter").ElementAt(i); //look it up in the task param xml XElement xADName = xDefault.XPathSelectElement("name"); string sADName = (xADName == null ? "" : xADName.Value); XElement xADValues = xDefault.XPathSelectElement("values"); //string sValues = (xValues == null ? "" : xValues.ToString()); //now we have the name of the parameter, go find it in the TASK param XML XElement xTaskParam = xTPDoc.XPathSelectElement("//parameter/name[. = '" + sADName + "']/.."); //NOTE! the /.. gets the parent of the name node! //if it doesn't exist in the task params, remove it from this document if (xTaskParam == null) { xDefault.Remove(); continue; } //and the "values" collection will be the 'next' node XElement xTaskParamValues = xTaskParam.XPathSelectElement("values"); //so... it might be //a) just an oev (original encrypted value) so de-base64 it //b) a value flagged for encryption //note we don't care about dirty unencrypted values... they'll compare down below just fine. //is it encrypted? bool bEncrypted = false; if (xTaskParam.Attribute("encrypt") != null) bEncrypted = dc.IsTrue(xTaskParam.Attribute("encrypt").Value); if (bEncrypted) { foreach (XElement xVal in xADValues.XPathSelectElements("value")) { if (xVal.HasAttributes) { //a) is it an oev? unpackJSON it (that's just an obfuscation wrapper) if (xVal.Attribute("oev") != null) { if (dc.IsTrue(xVal.Attribute("oev").Value)) { xVal.Value = ui.unpackJSON(xVal.Value); xVal.SetAttributeValue("oev", null); } } //b) is it do_encrypt? (remove the attribute to keep the db clutter down) if (xVal.Attribute("do_encrypt") != null) { xVal.Value = dc.EnCrypt(xVal.Value); xVal.SetAttributeValue("do_encrypt", null); } } } } //now that the encryption is sorted out, // if the combined values of the parameter happens to match what's on the task // we just remove it. //we're doing combined because of lists (the whole list must match for it to be a dupe) //it's easy to look at all the values in a node with the node.Value property. //but we'll have to manually concatenate all the oev attributes string sTaskVals = ""; string sDefVals = ""; if (bEncrypted) { // the task document already has the oev obfuscated foreach (XAttribute xa in xTaskParamValues.Elements("value").Attributes("oev")) { sTaskVals += xa.Value; } //but the XML we just got from the client doesn't... it's in the value. foreach (XElement xe in xADValues.Elements("value")) { sDefVals += ui.packJSON(xe.Value); } if (sTaskVals.Equals(sDefVals)) { xDefault.Remove(); continue; } } else { if (xTaskParamValues.Value.Equals(xADValues.Value)) { xDefault.Remove(); continue; } } } //done sOverrideXML = xADDoc.ToString(SaveOptions.DisableFormatting); //FINALLY, we have an XML that represents only the differences we wanna save. sSQL = "update ecotemplate_action set" + " parameter_defaults = '" + sOverrideXML + "'" + " where action_id = '" + sActionID + "'"; if (!dc.sqlExecuteUpdate(sSQL, ref sErr)) throw new Exception("Unable to update Eco Template Action [" + sActionID + "]." + sErr); ui.WriteObjectChangeLog(Globals.acObjectTypes.EcoTemplate, sActionID, sActionID, "Action default parameters updated: [" + sOverrideXML + "]"); } else { throw new Exception("Unable to update Eco Template Action. Missing or invalid Action ID."); } } catch (Exception ex) { throw ex; } return; }