Tuesday, April 1, 2014

Mobile Approvals using Integration Broker and Node.js

If you read this blog then you know I have already blogged about using our ESB, DataPower, to process mobile approvals. The concept is to have integration broker server up really simple HTML forms and use a web server or ESB to send the request to Integration broker.  Integration broker then responds with some HTML that looks like this:


Much of the code that generates this HTML is shown with the previous post,  however I omitted the HTML objects.  So looking at how the HTML gets generated and then wrapped in an xml document, this is the code that creates the form for the mobile user to act on.

&ResponseXML = CreateXmlDoc(GetHTMLText(HTML.ZZ_MYAPPROVAL_XML, GetHTMLText(HTML.ZZ_MYAPPROVAL_WRAPPER, %This.postURL, GenToken(), GetHTMLText(HTML.ZZ_MYAPPROVAL_ABS, &processId, &bgn_dt, &emplid, &empl_rcd, &end_dt, &pin_take_num, &transaction_id, &transaction_nbr, &eoawdefn_id, &punch_type, &zz_job_opening_id, &bgn_dt, &end_dt, &gp_pin.DESCR.Value, &reason, &GP_ABS_EVENT.DURATION_ABS.Value, "8", &Util.getUserNamebyEmplid(&emplid)))));

 Starting with the inner most HTML object we find the HTML.ZZ_MYAPPROVAL_ABS:
         

<h2>Absence Request</h2>
<h4>%Bind(:18)</h4>
<br>
     
Start Date: <input type="text" name="StDt"  value="%bind(:12)" readonly><br>
End Date: <input type="text" name="EndDt"  value="%bind(:13)" readonly><br>
Absence Name: <input type="text" name="Name"  value="%Bind(:14)" readonly><br>
Duration: <input type="text" name="Dur"  value="%bind(:17) Hours**" readonly><br>


<br><br>

<input type="submit" value="Approve"  onclick="submitAction(document.approval,'%bind(:1)','%bind(:2)','%bind(:3)','%bind(:4)','%bind(:5)','%bind(:6)','%bind(:7)','%bind(:8)','%bind(:9)','%bind(:10)','%bind(:11)', 'Approve')" >
<input type="submit" value="Deny"  onclick="submitAction(document.approval,'%bind(:1)','%bind(:2)','%bind(:3)','%bind(:4)','%bind(:5)','%bind(:6)','%bind(:7)','%bind(:8)','%bind(:9)','%bind(:10)','%bind(:11)','Deny')" >
<input type="submit" value="Worklist"  onclick="submitAction(document.approval,' ','%bind(:2)','%bind(:3)','%bind(:4)','%bind(:5)','%bind(:6)','%bind(:7)','%bind(:8)','%bind(:9)','%bind(:10)','%bind(:11)','')" >

<p>If you click the "Submit" button, the form-data will be sent to Integration Broker.</p> 


The HTML above then gets wrapped by the HTML.ZZ_MYAPPROVAL_WRAPPER.


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="application/x-www-form-urlencoded;charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.css" />
//<link rel="stylesheet" href="http://shell.acmelabs.io/~kweaver/css/umb-custom-theme.css" />
//<link rel="stylesheet" href="http://www.shell.acmelabs.io/~kweaver/css/umb-custom-theme.css" />
<link rel="stylesheet" href="http://www.connectedchef.com/umb-custom-theme.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.js">

</head>
<script> 
function submitAction(form,  processid, bgn_dt, emplid, empl_rcd, end_dt, pin_take_num, transactionid, transactionnbr, eoawdefn_id, punch_type, zz_job_opening_id, userValue)
{
//alert('starting process');
// set form values


form.processid_e.value = processid;
form.bgn_dt_e.value = bgn_dt;
form.emplid_e.value = emplid;
form.empl_rcd_e.value = empl_rcd;
form.end_dt_e.value = end_dt;
form.pin_take_num_e.value = pin_take_num;
form.transactionid_e.value = transactionid;
form.transaction_nbr_e.value = transactionnbr;
form.eoawdefn_id_e.value = eoawdefn_id;
form.punch_type_e.value = punch_type;
form.zz_job_opening_id_e.value = zz_job_opening_id;
form.useraction_e.value = userValue;
// form.Submit.disabled=true;
form.submit();
}

</script>

<body>
<div id="container_form" data-role="page"  data-theme="a">
<header data-role="header" data-theme="a">
<h1>myApprovals</h1>
 </header>

<form   action="%BIND(:1)" data-ajax="false"  id="approval" name="approval" method="Post" > 
<input type="hidden" name="pstoken_e" value="%BIND(:2)">

<input type="hidden" name="processid_e" value=" ">
<input type="hidden" name="bgn_dt_e" value=" ">
<input type="hidden" name="emplid_e" value=" ">
<input type="hidden" name="empl_rcd_e" value=" ">
<input type="hidden" name="end_dt_e" value=" ">
<input type="hidden" name="pin_take_num_e" value=" ">
<input type="hidden" name="transactionid_e" value=" ">
<input type="hidden" name="transaction_nbr_e" value=" ">
<input type="hidden" name="eoawdefn_id_e" value=" "> 
<input type="hidden" name="punch_type_e" value=" ">
<input type="hidden" name="zz_job_opening_id_e" value=" ">
<input type="hidden" name="useraction_e" value=""> 

%bind(:3) 

</form> 



</body>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.js"></script>
</html>
 
And finally these to HTML objects get wrapped in then HTML.ZZ_MYAPPROVAL_XML

<?xml version="1.0"?>
<data psnonxml="Yes"><![CDATA[
%BIND(:1)
]]></data>
 
 
This last XML wrapper gets taken off via a transformation, but is essential in preventing tools pre 8.52 from creating an Integration Broker Error.


My final entry for this is my node.js web server code to facilitate the serving of the HTML content from Integration Broker. This code below will take any get and server up a simple login screen all posts that have the path /myApprovals then get posted to Integration Broker and the HTML response from above is then served to the device for the user to Approve or Deny.


var http = require('http');
var fs = require('fs');
var querystring = require('querystring');
var utils = require('util');
var request = require("request");

var options = {
  uri: "http://lsys113c.umb.com:13100/PSIGW//HttpListeningConnector?Operation=ZZ_MYAPPROVALS.v1&OperationType=Sync",
  method: "POST",
  form: {
  }
};


var templateEngine = function (template, data) {
  var vars = template.match(/\{\w+\}/g);

  if (!vars) {
    return template;
  }

  var nonVars = template.split(/\{\w+\}/g);
  var output = '';

  for (var i = 0; i < nonVars.length; i++) {
    output += nonVars[i];

    if (i < vars.length) {
      var key = vars[i].replace(/[\{\}]/g, '');
      output += data[key]
    }
  }

  return output;
};

http.createServer(function (req, res) {
  // set up some routes
  switch(req.url) {
    case '/':
  //  console.log("[200] " + req.method + " to " + req.url);
   res.statusCode = 200;
   res.setHeader("Content-Type", "text/html");

  fs.readFile('login.html', function (err, data) {
    if (!err) {
      res.write(templateEngine(data.toString(), {})); // use our template engine here
      res.end();
    }
  });
  break;


   case '/myApprovals':

  if (req.method == 'POST') {
//    console.log("[200] " + req.method + " to " + req.url);
    var fullBody = '';

    function PostData(toIB) {

     options.form = toIB;

     request(options, function(error, response, body) {
     res.writeHead(200, "OK", {'Content-Type': 'text/html'});
     res.write(body);
     res.end();
     });

    };
    
    req.on('data', function(chunk) {
      // append the current chunk of data to the fullBody variable
      fullBody += chunk.toString();
    });
    
    req.on('end', function() {
       // parse the received body data
      var decodedBody = querystring.parse(fullBody);
  //    console.log(decodedBody);
      var psoftRes = PostData(decodedBody);

    });
    
  } else {
    console.log("[405] " + req.method + " to " + req.url);
    res.writeHead(405, "Method not supported", {'Content-Type': 'text/html'});
    res.end('<html><head><title>405 - Method not supported</title></head><body><h1>Method not supported.</h1></body></html>');
  }
  
  break;

    default:
      res.writeHead(404, "Not found", {'Content-Type': 'text/html'});
      res.end('<html><head><title>404 - Not found</title></head><body><h1>Not found.</h1></body></html>');
      console.log("[404] " + req.method + " to " + req.url);
  };
}).listen(8080); 


No comments:

Post a Comment