Clarity

  • 1.  Execute XOG Write via Javascript Function

    Posted Aug 29, 2017 11:21 PM

    OK folks, I'm stuck and hoping someone can share their knowledge.  I'm launching a javascript function when an event occurs on a web page. The function will update a Task status (using XOG).

     

    Everything is happy until I try to initialize, aim and fire my XMLHTTPRequest, and I wonder if someone can point out what I've missed.  Here's the function:

    function ExecuteTaskUpdate(taskID, taskStatus)
    {

    //Obtain Server name from URL
    var url = window.document.URL;
    var ServerName = url.substring(7,url.indexOf("niku/")-1);
    var xog_url = "https://" + ServerName + "/niku/xog";

    // Retrieve Project ID from URL
    var n = url.length;
    var n = (n-7);
    var projID = url.substring(n, (n+7));

    // Get User's SessionID from Cookie
    UserSessionID=window.clarity.session.sessionId;

    //Query the DB for the set of Tasks
    var TaskQueryCode="fon_proj_phase_task";
    var TaskQueryFilterField="task_int_id";
    var TaskQueryFilterValue= taskID;

    //Query Callback is not being used
    var TaskQueryCallback="";

    //Execute the query using the logged user's sessionId
    var Result=ExecuteClarityQueryAsUser(ServerName, TaskQueryCode, TaskQueryFilterField, TaskQueryFilterValue, TaskQueryCallback);
    var returnedString = String(Result.responseText);

    // Creates the XML object with the TextResponse from the Query
    var xmlobject = crossBrowserXMLLoad(Result.responseText);

    //Get records returned
    var taskitems = xmlobject.getElementsByTagName("Record");
    totaltasks = taskitems.length;

    for (var i = 0 ; i < totaltasks ; i++)
    {

    var task = taskitems[i];
    var projectID = task.getElementsByTagName("project_id")[0].firstChild.nodeValue;
    var projectName = task.getElementsByTagName("project_name")[0].firstChild.nodeValue;
    var taskCode = task.getElementsByTagName("task_id")[0].firstChild.nodeValue;
    var taskName = task.getElementsByTagName("task_name")[0].firstChild.nodeValue;
    var taskStart = task.getElementsByTagName("start_date")[0].firstChild.nodeValue;
    var taskFinish = task.getElementsByTagName("finish_date")[0].firstChild.nodeValue;
    var taskOutline = task.getElementsByTagName("outline_level")[0].firstChild.nodeValue;

    //Build up the XOG Write File
    if (taskStatus == 0)
    {
    var xw = "?<xml version=\"1.0\" encoding=\"utf-8\"?>" +
    '<soapenv:Envelope ' +
    ' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"' +
    ' xmlns:core="jelly:core"' +
    ' xmlns:file="jelly:com.niku.union.gel.FileTagLibrary" ' +
    ' xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" ' +
    ' xmlns:soap="jelly:com.niku.union.gel.SOAPTagLibrary" ' +
    ' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' +
    ' xmlns:sql="jelly:sql" ' +
    ' xmlns:util="jelly:util" ' +
    ' xmlns:xog="http://www.niku.com/xog" ' +
    ' xmlns:xsd="http://www.w3.org/2001/XMLSchem\" ' +
    ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
    ' <soapenv:Header> ' +
    '<xog:Auth>' +
    ' <xog:SessionID>' + UserSessionID + '</xog:SessionID>' +
    '</xog:Auth>' +
    '</soapenv:Header>' +
    '<soapenv:Body>' +
    '<NikuDataBus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/nikuxog_project.xsd">' +
    '<Header action="write" externalSource="NIKU" objectType="project" version="15.2.0.213"/>' +
    '<Projects>' +
    '<Project name="' + projectName + '" projectID="' + projectID + '">' +
    '<Tasks>' +
    '<Task finish="' + taskFinish + '" internalTaskID="' + taskID + '" name="' + taskName + '" outlineLevel="' + taskOutline + '" percComp="' + "0" + '" start="' + taskStart + '" status="' + "0" + '" taskID="' + taskCode + '"/>' +
    '</Tasks>' +
    '</Project>' +
    '</Projects>' +
    '</NikuDataBus>' +
    '</soapenv:Body>' +
    '<soapenv:Envelope>'
    } else if (taskStatus == 1)
    {
    var xw = "?<xml version=\"1.0\" encoding=\"utf-8\"?>" +
    '<soapenv:Envelope ' +
    ' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"' +
    ' xmlns:core="jelly:core"' +
    ' xmlns:file="jelly:com.niku.union.gel.FileTagLibrary" ' +
    ' xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" ' +
    ' xmlns:soap="jelly:com.niku.union.gel.SOAPTagLibrary" ' +
    ' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' +
    ' xmlns:sql="jelly:sql" ' +
    ' xmlns:util="jelly:util" ' +
    ' xmlns:xog="http://www.niku.com/xog" ' +
    ' xmlns:xsd="http://www.w3.org/2001/XMLSchem\" ' +
    ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
    ' <soapenv:Header> ' +
    '<xog:Auth>' +
    ' <xog:SessionID>' + UserSessionID + '</xog:SessionID>' +
    '</xog:Auth>' +
    '</soapenv:Header>' +
    '<soapenv:Body>' +
    '<NikuDataBus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/nikuxog_project.xsd">' +
    '<Header action="write" externalSource="NIKU" objectType="project" version="15.2.0.213"/>' +
    '<Projects>' +
    '<Project name="' + projectName + '" projectID="' + projectID + '">' +
    '<Tasks>' +
    '<Task finish="' + taskFinish + '" internalTaskID="' + taskID + '" name="' + taskName + '" outlineLevel="' + taskOutline + '" percComp="' + "0.99" + '" start="' + taskStart + '" status="' + "1" + '" taskID="' + taskCode + '"/>' +
    '</Tasks>' +
    '</Project>' +
    '</Projects>' +
    '</NikuDataBus>' +
    '</soapenv:Body>' +
    '<soapenv:Envelope>'
    } else if (taskStatus == 2)
    {
    var xw = "?<xml version=\"1.0\" encoding=\"utf-8\"?>" +
    '<soapenv:Envelope ' +
    ' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"' +
    ' xmlns:core="jelly:core"' +
    ' xmlns:file="jelly:com.niku.union.gel.FileTagLibrary" ' +
    ' xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" ' +
    ' xmlns:soap="jelly:com.niku.union.gel.SOAPTagLibrary" ' +
    ' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' +
    ' xmlns:sql="jelly:sql" ' +
    ' xmlns:util="jelly:util" ' +
    ' xmlns:xog="http://www.niku.com/xog" ' +
    ' xmlns:xsd="http://www.w3.org/2001/XMLSchem\" ' +
    ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
    ' <soapenv:Header> ' +
    '<xog:Auth>' +
    ' <xog:SessionID>' + UserSessionID + '</xog:SessionID>' +
    '</xog:Auth>' +
    '</soapenv:Header>' +
    '<soapenv:Body>' +
    '<NikuDataBus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/nikuxog_project.xsd">' +
    '<Header action="write" externalSource="NIKU" objectType="project" version="15.2.0.213"/>' +
    '<Projects>' +
    '<Project name="' + projectName + '" projectID="' + projectID + '">' +
    '<Tasks>' +
    '<Task finish="' + taskFinish + '" internalTaskID="' + taskID + '" name="' + taskName + '" outlineLevel="' + taskOutline + '" percComp="' + "1" + '" start="' + taskStart + '" status="' + "2" + '" taskID="' + taskCode + '"/>' +
    '</Tasks>' +
    '</Project>' +
    '</Projects>' +
    '</NikuDataBus>' +
    '</soapenv:Body>' +
    '<soapenv:Envelope>'
    }
    //This is where things go horribly wrong...


    //launch a new XMLHTTP request
    var xmlhttp;
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("POST", xog_url, true);
    var xmlDoc = xmlhttp.responseXML;

    //Initialize, aim and fire
    xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
    //Did we strike our target?
    var xmlDoc = xmlhttp.responseXML;

    console.log("XML String: " + xmlhttp.responseText);
    try {
    var xogOutput = xmlDoc.getElementsByTagName("XOGOutput")[0];
    xogOutput.parentNode.removeChild(xogOutput);
    } catch (err) {
    //Did we miss altogether?
    console.log(err.message);
    }
    //What is the Response to our http request?
    console.log(xmlhttp.responseText);
    }
    }

    //Right, send it all away...
    xmlhttp.setRequestHeader("Content-Type", "text/xml");
    xmlhttp.send(xw);
    }

    }

    I can build execute the query ("fon_proj_phase_task") and get back all of the information I need.  I can build my XOG write request, which runs happily and successfully in the IT-ROI XOG and Query Bridge. So, I'm missing something simple and vital in the XMLHTTPRequest.

    The error in the browser Console is "Failed to load resource: the server responded with a status of 400()"

    Any ideas will be very gratefully received...

     

    Edit: version 15.2, ondemand



  • 2.  Re: Execute XOG Write via Javascript Function
    Best Answer

    Posted Aug 30, 2017 11:24 AM

    The 400 code is a bad request.  I would check your xog_url to make sure it is correct.

     

    V/r,

    Gene



  • 3.  Re: Execute XOG Write via Javascript Function

    Posted Sep 01, 2017 05:46 PM

    Absolutely right, Gene, it was the URL.

    I tried various combinations and permutations but couldn't figure it out. So, since it's just for a Proof of Concept that I'll hand off to the clever people to turn into something "real", I've changed it to use the (not-supported-by-CA) Rest API.



  • 4.  Re: Execute XOG Write via Javascript Function

    Posted Sep 02, 2017 01:08 PM

    Looking pass the bad request, I noticed that you didn't set the SOAPAction in the request header.

     

              xmlhttp.setRequestHeader("SOAPAction", "http://www.niku.com/xog/Object/WriteProject");

     

    I did a little refactor on your script but can not test it as I don't have the ExecuteClarityQueryAsUser and crossBrowserXMLLoad functions.

     

    function ExecuteTaskUpdate(taskID, taskStatus) {

         //Obtain Server name from URL
         var url = window.document.URL;
         var ServerName = url.substring(7, url.indexOf("niku/") - 1);
         var xog_url = "https://" + ServerName + "/niku/xog";

         // Retrieve Project ID from URL
         var projID = url.substring((url.length-7), url.length);

         // Get User's SessionID from Cookie
         UserSessionID = window.clarity.session.sessionId;

         //Query the DB for the set of Tasks
         var TaskQueryCode = "fon_proj_phase_task";
         var TaskQueryFilterField = "task_int_id";
         var TaskQueryFilterValue = taskID;

         //Query Callback is not being used
         var TaskQueryCallback = "";

         //Execute the query using the logged user's sessionId
         var Result = ExecuteClarityQueryAsUser(ServerName, TaskQueryCode, TaskQueryFilterField, TaskQueryFilterValue, TaskQueryCallback);
         var returnedString = String(Result.responseText);

         // Creates the XML object with the TextResponse from the Query
         var xmlobject = crossBrowserXMLLoad(Result.responseText);

         //Get records returned
         var taskitems = xmlobject.getElementsByTagName("Record");
         totaltasks = taskitems.length;

         for (var i = 0; i < totaltasks; i++) {

              var task = taskitems[i];
              var projectID = task.getElementsByTagName("project_id")[0].firstChild.nodeValue;
              var projectName = task.getElementsByTagName("project_name")[0].firstChild.nodeValue;
              var taskCode = task.getElementsByTagName("task_id")[0].firstChild.nodeValue;
              var taskName = task.getElementsByTagName("task_name")[0].firstChild.nodeValue;
              var taskStart = task.getElementsByTagName("start_date")[0].firstChild.nodeValue;
              var taskFinish = task.getElementsByTagName("finish_date")[0].firstChild.nodeValue;
              var taskOutline = task.getElementsByTagName("outline_level")[0].firstChild.nodeValue;

              var xw = getXogPayload(UserSessionID, projectName, projectID, taskFinish, taskID, taskName, taskOutline, taskStart, taskCode, taskStatus);
              //This is where things go horribly wrong...

              //launch a new XMLHTTP request
              var xmlhttp;
              var xmlhttp = new XMLHttpRequest();
              xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
              xmlhttp.setRequestHeader("SOAPAction", "http://www.niku.com/xog/Object/WriteProject");
              xmlhttp.open("POST", xog_url, true);
              var xmlDoc = xmlhttp.responseXML;

              //Initialize, aim and fire
              xmlhttp.onreadystatechange = function () {
                   if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        //Did we strike our target?
                        var xmlDoc = xmlhttp.responseXML;

                        console.log("XML String: " + xmlhttp.responseText);
                        try {
                             var xogOutput = xmlDoc.getElementsByTagName("XOGOutput")[0];
                             xogOutput.parentNode.removeChild(xogOutput);
                        } catch (err) {
                             //Did we miss altogether?
                             console.log(err.message);
                        }
                        //What is the Response to our http request?
                        console.log(xmlhttp.responseText);
                   }
              }
              xmlhttp.send(xw);
         }

         function getXogPayload(UserSessionID, projectName, projectID, taskFinish, taskID, taskName, taskOutline, taskStart, taskCode, taskStatus) {

              var xw = [];
              var percComp = "0";
              if (taskStatus == 1) percComp = ".99";
              if (taskStatus == 2) percComp = "1";

              xw.pushxw.push('?<xml version="1.0" encoding="utf-8"?>');
              xw.push('<soapenv:Envelope ');
              xw.push(' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ');
              xw.push(' xmlns:core="jelly:core" ');
              xw.push(' xmlns:file="jelly:com.niku.union.gel.FileTagLibrary" ');
              xw.push(' xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" ');
              xw.push(' xmlns:soap="jelly:com.niku.union.gel.SOAPTagLibrary" ');
              xw.push(' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ');
              xw.push(' xmlns:sql="jelly:sql" ');
              xw.push(' xmlns:util="jelly:util" ');
              xw.push(' xmlns:xog="http://www.niku.com/xog" ');
              xw.push(' xmlns:xsd="http://www.w3.org/2001/XMLSchem" ');
              xw.push(' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> ');
              xw.push(' <soapenv:Header> ');
              xw.push(' <xog:Auth> <xog:SessionID>?</xog:SessionID> </xog:Auth> '.replace('?', UserSessionID));
              xw.push('</soapenv:Header> ');
              xw.push(' <soapenv:Body> ');
              xw.push(' <NikuDataBus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/nikuxog_project.xsd"> ');
              xw.push(' <Header action="write" externalSource="NIKU" objectType="project" version="15.2.0.213"/> ');
              xw.push(' <Projects> ');
              xw.push(' <Project name="?" '.replace('?', projectName));
              xw.push(' projectID="?" '.replace('?', projectID));
              xw.push(' <Tasks> ');
              xw.push(' <Task finish="?" '.replace('?', taskFinish));
              xw.push(' internalTaskID="?" '.replace('?', taskID));
              xw.push(' name="?" '.replace('?', taskName));
              xw.push(' outlineLevel="?" '.replace('?', taskOutline));
              xw.push(' percComp="?" ').replace('?', percComp));
              xw.push(' start="?" ').replace('?', taskStart));
              xw.push(' status="?" ').replace('?', taskStatus.toString()));
              xw.push(' taskID="?" /> ').replace('?', taskCode));
              xw.push(' </Tasks> ');
              xw.push(' </Project> ');
              xw.push(' </Projects> ');
              xw.push(' </NikuDataBus> ');
              xw.push(' </soapenv:Body> ');
              xw.push(' <soapenv:Envelope> ');
              return xw.join('');
         }
    }

     

    Maybe if you get a moment, you could see if that works.

     

    V/r,

    Gene



  • 5.  Re: Execute XOG Write via Javascript Function

    Posted Sep 03, 2017 10:40 PM

    Hi Gene

     

    Thanks very much for your help; I feel like I'm making progress.

     

    I'm still getting an error 400 reply, so I'm clearly still doing something wrong.  The responseText I'm getting back at line 50 (var xmlDoc = xmlhttp.responseXML) is empty. I'll keep flailing away at it, I'm sure I'm missing something rudimentary.

     

    I stole the functions ExecuteClarityQueryAsUser and CrossBrowserXMLLoad from this thread: Displaying Database Content in HTML Portlets 

     

    By the way ... using XOG I'm limited to updating Tasks which have a Task ID (prtask.prexternalid). Using the Rest API, I'm not constrained (notwithstanding that I'm also not supported) - Rest uses the Task Internal ID (prtask.prid) so I'm not relying on PMs or CA PPM to create a Task ID.



  • 6.  Re: Execute XOG Write via Javascript Function

    Posted Sep 05, 2017 12:02 AM
      |   view attached

    I've decided this is now good enough to prove the concept, and hand over to the developer to take to MVP stage.

     

    For anyone interested, it's an Agile-style board based on a HTML Portlet. Broken down by Phase, each Task/Milestone is a "ticket" on the board which can be dragged/dropped between 3 statuses: To Do, In Progress, Done.

     

    Proof of Concept -level XOG upload file attached if someone wants to take it and make it good...

    Attachment(s)

    zip
    Agile_Board.xml.zip   9 KB 1 version